├── CODEOWNERS ├── LICENSE ├── README.md ├── cifar_utils.py ├── defs.py ├── ex_00_tutorial_overview.ipynb ├── ex_01_remote_funcs.ipynb ├── ex_02_remote_objs.ipynb ├── ex_03_remote_classes.ipynb ├── ex_04_remote_classes_revisited.ipynb ├── ex_05_multiprocess_pool.ipynb ├── ex_06_ray_api_calls.ipynb ├── ex_07_ray_data.ipynb ├── ex_08_ray_air_in_ten_minutes.ipynb ├── ex_09_cifar_ray_air_example.ipynb ├── images ├── California_dataset.png ├── K-means_convergence.gif ├── Ray_AIR.png ├── ai_runtime.jpeg ├── air_ml_workflow.png ├── batch-inference.png ├── batch_predictor.png ├── batch_worker.jpg ├── batchpredict_code.png ├── checkpoints.jpeg ├── cifar-10.png ├── cls_actor_calls.png ├── data_code.png ├── data_highlight.png ├── data_prep.png ├── dataset-arch.png ├── dataset.png ├── dist_multi_pool.png ├── distributed_timeline.png ├── e2e_air.png ├── fashion-mnist-sprite.jpeg ├── gpu_saturation.png ├── hpo-neural-network-example.png ├── map_reduce.png ├── object_resolution.png ├── object_store.png ├── online_predictor.png ├── pipeline_window.jpg ├── py_2_ray.png ├── ray-air.svg ├── ray-logo.png ├── ray_air_pipeline.png ├── ray_arch.png ├── ray_basic_patterns.png ├── ray_dataset_pipeline.jpg ├── ray_logo.png ├── ray_task.png ├── ray_tune_report_launch_trainables.png ├── ray_tune_report_metrics.png ├── ray_worker_actor_1.png ├── ray_worker_actor_2.png ├── same_data_different_model.png ├── sequential_timeline.png ├── serve_code.png ├── serve_highlight.png ├── shared_memory.png ├── shared_memory_plasma_store.png ├── task_api_add_array.png ├── task_dependencies_graphs.png ├── train_code.png ├── train_highlight.png ├── trainer.png ├── trainer_worker.jpg ├── tune_code.png ├── tune_highlight.png ├── tuner.png ├── what-are-hyperparameters.png └── x_y_training_data.png ├── model_helper_utils.py ├── requirements.txt ├── retired ├── README.md ├── data │ ├── file_1.txt │ └── file_2.txt ├── ex_00_ray_tutorial_overview.ipynb ├── ex_01_remote_funcs.ipynb ├── ex_02_remote_objs.ipynb ├── ex_03_remote_classes.ipynb ├── ex_04_exploring_ray_api_calls.ipynb ├── ex_05_running_ray_clusters.ipynb ├── ex_06_xbgboost_train_tune.ipynb ├── ex_07_ray_tune_scklearn.ipynb ├── ex_08_model_serving_challenges.ipynb ├── ex_08_ray_air_in_ten_minutes.ipynb ├── ex_09_ray_serve_create_and_access_deployments.ipynb ├── ex_10_ray_serve_example.ipynb ├── ex_11_ray_serve_sentiment_tweets.ipynb ├── extra │ ├── ex_08_Understanding-Hyperparameter-Tuning.ipynb │ ├── ex_09_ray_train.ipynb │ ├── mp_all_nb.ipynb │ ├── ray_air_hugging_face.ipynb │ └── ray_data_nyc.ipynb ├── highly_parallel.ipynb ├── images │ ├── PatternsMLProduction.png │ ├── PyCon2022_Logo.png │ ├── actor_and_workders.png │ ├── architecture.png │ ├── func_class_deployment.png │ ├── func_class_deployment_2.png │ ├── object_resolution.png │ ├── ray-logo.png │ ├── ray_basic_patterns.png │ ├── ray_cluster.png │ ├── ray_serve_deployment_workflow.png │ ├── ray_serve_overview.png │ ├── ray_tune_dist_hpo.png │ ├── ray_worker_actor_1.png │ ├── ray_worker_actor_2.png │ ├── sentiment_analysis.jpeg │ ├── shared_memory.png │ ├── shared_memory_plasma_store.png │ ├── task_api_add_array.png │ ├── task_dependencies_graphs.png │ ├── task_ownership.png │ └── tune_flow.png ├── requirements.txt ├── slides │ ├── pyconus2022 │ │ └── pyconsus_slides.pdf │ └── weekly-demos │ │ └── presentation_slides.pdf ├── solutions │ ├── ex_01_solution.ipynb │ ├── ex_02_solution.ipynb │ ├── ex_03_solution.ipynb │ ├── ex_08_solution.ipynb │ └── ex_10_solution.ipynb └── submit.py ├── slides ├── pydata_nyc │ └── ray-core-tutorial-slides.pdf ├── pydata_seattle │ └── ray-core-tutorial-slides.pdf └── ucsd │ └── ucsd_lecture.pdf ├── solutions ├── ex_01_solution.ipynb ├── ex_02_solution.ipynb ├── ex_03_solution.ipynb ├── ex_04_solution.ipynb ├── ex_05_solution.ipynb └── ex_07_solutions.ipynb └── tasks_helper_utils.py /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @dmatrix 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Ray for Distributed Applications 2 | 3 | © 2019-2024, Anyscale. All Rights Reserved 4 | 5 | 6 | 7 | An introduction to [Ray](https://www.ray.io/), the system for scaling your Python and machine learning workloads from a laptop to a cluster. We'll start with a hands-on exploration of the core Ray APIs for distributed workloads, covering basic distributed Ray Core API patterns, and 8 | then move on to a quick introduction to one of Ray's native libraries: 9 | 10 | * Remote functions as tasks 11 | * Remote objects as futures 12 | * Remote classes as stateful actors 13 | * Quick introduction to Ray's data and Ray libraries 14 | 15 | ### Outline for this Tutorial Lesson 📖 16 | 17 | Divided into three modules, each module will take about an hour, combined with lecture and followed by hands-on 👩‍💻 exercises in class. 18 | 19 | ### Module 1 20 | * Lecture 20 mins 21 | * What is Ray and Why & Origins 22 | * Ray Component & Architecture 23 | * Ray Core API Decorators & Patterns 24 | * Notebooks & Exercises 25 | * Ray Functions as distribtued stateless tasks 26 | * Ray Objects as Distributed future objects 27 | * Ray Actors as distributed stateful services 28 | 29 | ### Module 2 30 | * Ray Actors Revisited: Understand a common pattern used in Ray native libraries 31 | * Tour of the Ray APIs: a quick look at common APIs and some tricks & tips if new to Ray 32 | * Distributed multiprocessing.Pool: different strategies to scale Python with Ray 33 | * Notebooks & Exercises 34 | 35 | ### Module 3 36 | * Brief Introduction to Ray Data: A gentle introduction to Ray Datasets 37 | * Brief Introduction to Ray AIR: A gentle introduction to Ray AIR 38 | 39 | ### Extra Modules 40 | * Additional and supplemental material to peruse at leisure time. 41 | 42 | ### In this tutorial, you will: 43 | * 👩‍💻Understand what the Ray ecosystem is and why to use it 44 | * 📖Learn Ray's Core basic APIs and Python APIs 45 | * 🧑‍💻Use Ray APIs to convert Python functions and classes into distributed stateless and stateful tasks 46 | * 🎛 Use Dashboard for inspection and observation 47 | * 🧑‍💻Discover the purpose of Ray native libraries and how to use them 48 | 49 | ### 🎓Prerequisite knowledge ### 50 | **Level**: Beginners or new to Ray 51 | 52 | * Familiarity with Python 3.9+ and basic programming concepts: lists, comprehensions, decorators, functions, dictionaries, classes, loops, exceptional handling, etc 53 | * Laptop with at least 8-16GB Memory with latest Chrome browser 54 | * Prior knowledge of Jupyter notebooks 55 | * Basic knowledge of machine learning concepts 56 | 57 | 58 | ## 👩 Setup instructions for local laptop 💻 59 | If you want to follow the material in class, please follow this instructions before class to setup your laptop. 60 | 61 | ### Using conda 62 | If you need to install Anaconda, follow the instructions [here](https://www.anaconda.com/products/distribution). 63 | If you already have Anaconda installed, consider running conda `upgrade --all.` 64 | 65 | 1. `conda create -n ray-core-tutorial python=3.10` 66 | 2. `conda activate ray-core-tutorial` 67 | 3. `git clone git@github.com:dmatrix/ray-core-tutorial.git` 68 | 4. `cd to ` 69 | 5. `python3 -m pip install -r requirements.txt` 70 | 7. `jupyter lab` 71 | 72 | ### Installing on Apple M1 73 | If you are using [Apple M1](https://docs.ray.io/en/latest/ray-overview/installation.html#m1-mac-apple-silicon-support) laptop 🍎 follow the following instructions: 74 | 75 | 1. `conda create -n ray-core-tutorial python=3.10` 76 | 2. `conda activate ray-core-tutorial` 77 | 3. `conda install grpcio=1.43.0 -c conda-forge` 78 | 4. `git clone git@github.com:dmatrix/ray-core-tutorial.git` 79 | 5. `cd to ` 80 | 6. `python3 -m pip install -r requirements.txt` 81 | 9. `jupyter lab` 82 | 83 | ### Using only pip 84 | 1. `git clone git@github.com:anyscale/ray-summit-2022-training.git` 85 | 2. `cd to ` 86 | 3. `python3 -m pip install -r requirements.txt` 87 | 5. `jupyter lab` 88 | 89 | Let's have 😜 fun with Ray! 90 | 91 | To start tutorials, [go here](ex_00_tutorial_overview.ipynb). 92 | 93 | And when you are finished, help us improve training. Please fill out this [survey](https://bit.ly/pydata-nyc-2022) 94 | -------------------------------------------------------------------------------- /cifar_utils.py: -------------------------------------------------------------------------------- 1 | 2 | from typing import Dict, Tuple 3 | 4 | import matplotlib.pyplot as plt 5 | import numpy as np 6 | import pandas as pd 7 | import tqdm 8 | 9 | import torch 10 | import torch.nn as nn 11 | import torch.optim as optim 12 | import torch.nn.functional as F 13 | import torchvision 14 | import torchvision.transforms as transforms 15 | 16 | from ray import train 17 | import ray.train.torch 18 | from ray.data.extensions import TensorArray 19 | from ray.air import session 20 | from ray.train.torch import TorchCheckpoint 21 | from ray.serve.http_adapters import NdArray 22 | 23 | CLASSES = ('plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck') 24 | 25 | transform = transforms.Compose( 26 | # this is the reason for normalizing (with mean, std) for each RGB channel 27 | # Normalization helps reduce or skewing and helps with faster CNN training 28 | # https://discuss.pytorch.org/t/understanding-transform-normalize/21730 29 | [transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))] 30 | ) 31 | 32 | def train_dataset_factory(): 33 | """ 34 | Download the train CiFAR 10 dataset into the root dir 35 | """ 36 | return torchvision.datasets.CIFAR10(root="~/data", 37 | download=True, 38 | train=True, 39 | transform=transform) 40 | 41 | def test_dataset_factory(): 42 | """ 43 | Download the test CiFAR 10 dataset into the root dir 44 | """ 45 | return torchvision.datasets.CIFAR10(root="~/data", 46 | download=True, 47 | train=False, 48 | transform=transform) 49 | 50 | def convert_batch_to_numpy(batch: Tuple[torch.Tensor, int]) -> Dict[str, np.ndarray]: 51 | images = np.array([image.numpy() for image, _ in batch]) 52 | labels = np.array([label for _, label in batch]) 53 | return {"image": images, "label": labels} 54 | 55 | class BasicBlock(nn.Module): 56 | expansion = 1 57 | 58 | 59 | def __init__(self, in_planes, planes, stride=1): 60 | super(BasicBlock, self).__init__() 61 | 62 | DROPOUT = 0.1 63 | 64 | self.conv1 = nn.Conv2d( 65 | in_planes, planes, kernel_size=3, stride=stride, padding=1, bias=False) 66 | self.bn1 = nn.BatchNorm2d(planes) 67 | self.dropout = nn.Dropout(DROPOUT) 68 | self.conv2 = nn.Conv2d(planes, planes, kernel_size=3, 69 | stride=1, padding=1, bias=False) 70 | self.bn2 = nn.BatchNorm2d(planes) 71 | self.dropout = nn.Dropout(DROPOUT) 72 | 73 | self.shortcut = nn.Sequential() 74 | if stride != 1 or in_planes != self.expansion*planes: 75 | self.shortcut = nn.Sequential( 76 | nn.Conv2d(in_planes, self.expansion*planes, 77 | kernel_size=1, stride=stride, bias=False), 78 | nn.BatchNorm2d(self.expansion*planes), 79 | nn.Dropout(DROPOUT) 80 | ) 81 | 82 | def forward(self, x): 83 | out = F.relu(self.dropout(self.bn1(self.conv1(x)))) 84 | out = self.dropout(self.bn2(self.conv2(out))) 85 | out += self.shortcut(x) 86 | out = F.relu(out) 87 | return out 88 | 89 | 90 | class ResNet(nn.Module): 91 | def __init__(self, block, num_blocks, num_classes=10): 92 | super(ResNet, self).__init__() 93 | self.in_planes = 64 94 | 95 | self.conv1 = nn.Conv2d(3, 64, kernel_size=3, 96 | stride=1, padding=1, bias=False) 97 | self.bn1 = nn.BatchNorm2d(64) 98 | self.layer1 = self._make_layer(block, 64, num_blocks[0], stride=1) 99 | self.layer2 = self._make_layer(block, 128, num_blocks[1], stride=2) 100 | self.layer3 = self._make_layer(block, 256, num_blocks[2], stride=2) 101 | self.layer4 = self._make_layer(block, 512, num_blocks[3], stride=2) 102 | self.linear = nn.Linear(512*block.expansion, num_classes) 103 | 104 | def _make_layer(self, block, planes, num_blocks, stride): 105 | strides = [stride] + [1]*(num_blocks-1) 106 | layers = [] 107 | for stride in strides: 108 | layers.append(block(self.in_planes, planes, stride)) 109 | self.in_planes = planes * block.expansion 110 | return nn.Sequential(*layers) 111 | 112 | def forward(self, x): 113 | out = F.relu(self.bn1(self.conv1(x))) 114 | out = self.layer1(out) 115 | out = self.layer2(out) 116 | out = self.layer3(out) 117 | out = self.layer4(out) 118 | out = F.avg_pool2d(out, 4) 119 | out = out.view(out.size(0), -1) 120 | out = self.linear(out) 121 | return F.log_softmax(out, dim=-1) 122 | 123 | 124 | def ResNet18(): 125 | return ResNet(BasicBlock, [2, 2, 2, 2]) 126 | 127 | 128 | def train_loop_per_worker(config): 129 | device = (ray.train.torch.get_device() if torch.cuda.is_available() else torch.device("cpu") 130 | ) 131 | 132 | # Prepare model for training. This involves moving the 133 | # model to appropriate device, putting into the training mode 134 | model = train.torch.prepare_model(ResNet18()) 135 | 136 | # Define loss function and optimizer 137 | criterion = nn.CrossEntropyLoss() 138 | optimizer = optim.SGD(model.parameters(), lr=config["lr"], momentum=0.9) 139 | 140 | # Fetch training Ray dataset from the session; this is automatically 141 | # distributed to the right worker node's process where the training 142 | # run 143 | train_dataset_shard = session.get_dataset_shard("train") 144 | 145 | # Iterate over epochs 146 | epochs = config.get("epochs", 10) 147 | batch_size = config.get("batch_size", 32) 148 | verbose = config.get("verbose", 0) 149 | lr = config.get("lr", 0.01) 150 | 151 | 152 | for epoch in tqdm.tqdm(range(epochs)): 153 | if verbose: 154 | print(f"Training epoch:{epoch+1}/{epochs} | batch_size:{batch_size} | lr:{lr}") 155 | 156 | train_loss = 0.0 157 | train_loss = 0.0 158 | total_images = 0 159 | 160 | # loop over batches for each epoch 161 | train_dataset_batches = train_dataset_shard.iter_torch_batches( 162 | batch_size=batch_size, 163 | ) 164 | for i, batch in enumerate(train_dataset_batches): 165 | # Get the inputs and labels 166 | inputs, labels = batch["image"], batch["label"] 167 | num_images = inputs.shape[0] 168 | inputs, labels = inputs.to(device), labels.to(device) 169 | 170 | # zero the parameter gradients 171 | optimizer.zero_grad() 172 | 173 | # forward + backward + optimize 174 | outputs = model(inputs) 175 | loss = criterion(outputs, labels) 176 | loss.backward() 177 | optimizer.step() 178 | 179 | train_loss += loss.item() * num_images 180 | total_images += num_images 181 | 182 | train_loss /= total_images 183 | metrics = dict(train_loss=train_loss) 184 | if verbose: 185 | print(f"training loss: {train_loss:.3f} | epoch: {epoch+1}/{epochs} | batch: {i+1}") 186 | 187 | # Create a Torch checkpoint from the models state dictionary after each 188 | # epoch and report the metrics 189 | checkpoint = TorchCheckpoint.from_state_dict(model.module.state_dict()) 190 | session.report(metrics, checkpoint=checkpoint) 191 | 192 | def convert_logits_to_classes(df): 193 | best_class = df["predictions"].map(lambda x: x.argmax()) 194 | df["prediction"] = best_class 195 | return df 196 | 197 | def calculate_prediction_scores(df): 198 | df["correct"] = df["prediction"] == df["label"] 199 | return df[["prediction", "label", "correct"]] 200 | 201 | def json_to_numpy(payload: NdArray) -> pd.DataFrame: 202 | """Accepts an NdArray JSON from an HTTP body and converts it to a Numpy Array.""" 203 | # Have to explicitly convert to float since np.array reads as a double. 204 | arr = np.array(payload.array, dtype=np.float32) 205 | return arr 206 | 207 | def to_prediction_cls(lst): 208 | max_value = max(lst) 209 | idx = lst.index(max_value) 210 | cls = CLASSES[idx] 211 | return idx,cls 212 | 213 | def img_show(img): 214 | img = img / 2 + 0.5 # unnormalize 215 | # npimg = img.numpy() 216 | plt.imshow(np.transpose(img, (1, 2, 0))) 217 | plt.show() -------------------------------------------------------------------------------- /defs.py: -------------------------------------------------------------------------------- 1 | import multiprocessing as mp 2 | import numpy as np 3 | import scipy.signal 4 | 5 | 6 | def get_cpu_count(): 7 | return mp.cpu_count() 8 | 9 | 10 | def is_prime(n): 11 | for divisor in range(2, int(n ** 0.5) + 1): 12 | if n % divisor == 0: 13 | return 0 14 | return 1 15 | 16 | def inefficient_fib(n=None): 17 | """Compute intensive calculation for the nth fibonacci number""" 18 | if n <= 1: 19 | return n 20 | return inefficient_fib(n - 1) + inefficient_fib(n - 2) 21 | 22 | iterations_count = iterations_count = round(1e4) 23 | def complex_operation_numpy(index): 24 | data = np.ones(iterations_count) 25 | val = np.exp(data) * np.sinh(data) 26 | return val.sum() 27 | 28 | def f_ray_image_signal(args): 29 | image, random_filter = args 30 | # Do some image processing: convolve two 2-dimensional arrays. 31 | return scipy.signal.convolve2d(image, random_filter)[::5, ::5] 32 | 33 | def f_py_image_signal(args): 34 | image, random_filter = args 35 | # Do some image processing: convolve two 2-dimensional arrays. 36 | return scipy.signal.convolve2d(image, random_filter)[::5, ::5] 37 | 38 | -------------------------------------------------------------------------------- /ex_00_tutorial_overview.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Ray Tutorial Basic Core APIs - Overview\n", 8 | "\n", 9 | "© 2021-2022, Anyscale. All Rights Reserved\n", 10 | "\n", 11 | "\n", 12 | "\n", 13 | "## About This Tutorial\n", 14 | "\n", 15 | "\n", 16 | "See the instructions in the [README](README.md) tutorial overview to set up your environment to use this tutorial if you want to run this on your laptop. If you using Anyscale hosted enviroment for this class, then you don't have to do anything. " 17 | ] 18 | }, 19 | { 20 | "cell_type": "markdown", 21 | "metadata": {}, 22 | "source": [ 23 | "| | Lesson | Description |\n", 24 | "| :-- | :----- | :---------- |\n", 25 | "| | **Module 1** | **Ray Tasks, Ray Objects, and Ray Actors** |\n", 26 | "| | Table of contents | Overview of this tutorial. |\n", 27 | "| 01 | [Ray Remote Functions ](ex_01_remote_funcs.ipynb) |The remote function as stateless tasks pattern. |\n", 28 | "| 02 | [Ray Remote Objects](ex_02_remote_objs.ipynb) |The remote objects, stored in a immutable distributed store, as futures pattern. |\n", 29 | "| 03 | [Ray Remote Classes](ex_03_remote_classes.ipynb)| The remote class as a distributed and scalable stateful service pattern.|\n", 30 | "| | **Module 2** | **Focus on Ray Actor Tree Patterns, Ray Multiprocess Pool for clusters, Ray API Tour** |\n", 31 | "| 04 | [Ray Remote Classes Revisited](ex_04_remote_classes_revisited.ipynb) |The stateful tree Actor pattern: Understand a common pattern used in Ray native libraries to scale workloads |\n", 32 | "| 05 | [Ray Multiprocess Pool for clusters](ex_05_multiprocess_pool.ipynb) | Ray's multiprocess pool for clusters: examine different strategies to scale Python with Ray|\n", 33 | "| 06 | [Ray API Calls Tour](ex_06_ray_api_calls.ipynb) |A look at common Ray API calls and some tricks & tips if new to Ray |\n", 34 | "| | **Module 3** | **Brief introduction Ray Data** |\n", 35 | "| 07 | [Introduction to Ray Data](ex_07_ray_data.ipynb) | A gentle introduction to Ray Datasets 10 minutes|\n", 36 | "| 08 | [Introduction to Ray AIR](ex_08_ray_air_in_ten_minutes.ipynb) | A gentle introduction to Ray AIR in 10 minutes |\n", 37 | "| 09 | [CiFAR-10 Classification](ex_09_cifar_ray_air_example.ipynb) | An end to end ML example using Ray AIR|\n" 38 | ] 39 | } 40 | ], 41 | "metadata": { 42 | "kernelspec": { 43 | "display_name": "Python 3 (ipykernel)", 44 | "language": "python", 45 | "name": "python3" 46 | }, 47 | "language_info": { 48 | "codemirror_mode": { 49 | "name": "ipython", 50 | "version": 3 51 | }, 52 | "file_extension": ".py", 53 | "mimetype": "text/x-python", 54 | "name": "python", 55 | "nbconvert_exporter": "python", 56 | "pygments_lexer": "ipython3", 57 | "version": "3.8.13" 58 | } 59 | }, 60 | "nbformat": 4, 61 | "nbformat_minor": 4 62 | } 63 | -------------------------------------------------------------------------------- /images/California_dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/California_dataset.png -------------------------------------------------------------------------------- /images/K-means_convergence.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/K-means_convergence.gif -------------------------------------------------------------------------------- /images/Ray_AIR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/Ray_AIR.png -------------------------------------------------------------------------------- /images/ai_runtime.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ai_runtime.jpeg -------------------------------------------------------------------------------- /images/air_ml_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/air_ml_workflow.png -------------------------------------------------------------------------------- /images/batch-inference.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/batch-inference.png -------------------------------------------------------------------------------- /images/batch_predictor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/batch_predictor.png -------------------------------------------------------------------------------- /images/batch_worker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/batch_worker.jpg -------------------------------------------------------------------------------- /images/batchpredict_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/batchpredict_code.png -------------------------------------------------------------------------------- /images/checkpoints.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/checkpoints.jpeg -------------------------------------------------------------------------------- /images/cifar-10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/cifar-10.png -------------------------------------------------------------------------------- /images/cls_actor_calls.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/cls_actor_calls.png -------------------------------------------------------------------------------- /images/data_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/data_code.png -------------------------------------------------------------------------------- /images/data_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/data_highlight.png -------------------------------------------------------------------------------- /images/data_prep.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/data_prep.png -------------------------------------------------------------------------------- /images/dataset-arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/dataset-arch.png -------------------------------------------------------------------------------- /images/dataset.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/dataset.png -------------------------------------------------------------------------------- /images/dist_multi_pool.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/dist_multi_pool.png -------------------------------------------------------------------------------- /images/distributed_timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/distributed_timeline.png -------------------------------------------------------------------------------- /images/e2e_air.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/e2e_air.png -------------------------------------------------------------------------------- /images/fashion-mnist-sprite.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/fashion-mnist-sprite.jpeg -------------------------------------------------------------------------------- /images/gpu_saturation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/gpu_saturation.png -------------------------------------------------------------------------------- /images/hpo-neural-network-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/hpo-neural-network-example.png -------------------------------------------------------------------------------- /images/map_reduce.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/map_reduce.png -------------------------------------------------------------------------------- /images/object_resolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/object_resolution.png -------------------------------------------------------------------------------- /images/object_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/object_store.png -------------------------------------------------------------------------------- /images/online_predictor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/online_predictor.png -------------------------------------------------------------------------------- /images/pipeline_window.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/pipeline_window.jpg -------------------------------------------------------------------------------- /images/py_2_ray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/py_2_ray.png -------------------------------------------------------------------------------- /images/ray-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray-logo.png -------------------------------------------------------------------------------- /images/ray_air_pipeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_air_pipeline.png -------------------------------------------------------------------------------- /images/ray_arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_arch.png -------------------------------------------------------------------------------- /images/ray_basic_patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_basic_patterns.png -------------------------------------------------------------------------------- /images/ray_dataset_pipeline.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_dataset_pipeline.jpg -------------------------------------------------------------------------------- /images/ray_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_logo.png -------------------------------------------------------------------------------- /images/ray_task.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_task.png -------------------------------------------------------------------------------- /images/ray_tune_report_launch_trainables.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_tune_report_launch_trainables.png -------------------------------------------------------------------------------- /images/ray_tune_report_metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_tune_report_metrics.png -------------------------------------------------------------------------------- /images/ray_worker_actor_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_worker_actor_1.png -------------------------------------------------------------------------------- /images/ray_worker_actor_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/ray_worker_actor_2.png -------------------------------------------------------------------------------- /images/same_data_different_model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/same_data_different_model.png -------------------------------------------------------------------------------- /images/sequential_timeline.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/sequential_timeline.png -------------------------------------------------------------------------------- /images/serve_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/serve_code.png -------------------------------------------------------------------------------- /images/serve_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/serve_highlight.png -------------------------------------------------------------------------------- /images/shared_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/shared_memory.png -------------------------------------------------------------------------------- /images/shared_memory_plasma_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/shared_memory_plasma_store.png -------------------------------------------------------------------------------- /images/task_api_add_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/task_api_add_array.png -------------------------------------------------------------------------------- /images/task_dependencies_graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/task_dependencies_graphs.png -------------------------------------------------------------------------------- /images/train_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/train_code.png -------------------------------------------------------------------------------- /images/train_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/train_highlight.png -------------------------------------------------------------------------------- /images/trainer.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/trainer.png -------------------------------------------------------------------------------- /images/trainer_worker.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/trainer_worker.jpg -------------------------------------------------------------------------------- /images/tune_code.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/tune_code.png -------------------------------------------------------------------------------- /images/tune_highlight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/tune_highlight.png -------------------------------------------------------------------------------- /images/tuner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/tuner.png -------------------------------------------------------------------------------- /images/what-are-hyperparameters.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/what-are-hyperparameters.png -------------------------------------------------------------------------------- /images/x_y_training_data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/images/x_y_training_data.png -------------------------------------------------------------------------------- /model_helper_utils.py: -------------------------------------------------------------------------------- 1 | import time 2 | from typing import Tuple, Dict, Any 3 | from sklearn.datasets import fetch_california_housing 4 | from sklearn.ensemble import RandomForestRegressor 5 | from sklearn.tree import DecisionTreeRegressor 6 | from sklearn.metrics import mean_squared_error 7 | from sklearn.model_selection import train_test_split 8 | import xgboost as xgb 9 | import ray 10 | 11 | # states to inspect 12 | STATES = ["INITIALIZED", "RUNNING", "DONE"] 13 | 14 | DECISION_TREE_CONFIGS = {"max_depth": 15, 15 | "name": "decision_tree"} 16 | 17 | RANDOM_FOREST_CONFIGS = {"n_estimators": 150, 18 | "name": "random_forest"} 19 | 20 | XGBOOST_CONFIGS = {"max_depth": 10, 21 | "n_estimators": 150, 22 | "lr": 0.1, 23 | "eta": 0.3, 24 | "colsample_bytree": 1, 25 | "name": "xgboost"} 26 | 27 | class ActorCls: 28 | """ 29 | Base class for our Ray Actor workers models 30 | """ 31 | def __init__(self, configs: Dict[Any, Any]) -> None: 32 | self.configs = configs 33 | self.name = configs["name"] 34 | self.state = STATES[0] 35 | self.X, self.y = None, None 36 | self.X_train, self.X_test = None, None 37 | self.y_train, self.y_test = None, None 38 | self.model = None 39 | 40 | def get_name(self) -> str: 41 | return self.name 42 | 43 | def get_state(self) -> str: 44 | return self.state 45 | 46 | 47 | def _prepare_data_and_model(self) -> None: 48 | self.X, self.y = fetch_california_housing(return_X_y=True, as_frame=True) 49 | self.X_train, self.X_test, self.y_train, self.y_test = train_test_split(self.X, self.y, test_size=0.2, random_state=4) 50 | 51 | def train_and_evaluate_model(self) -> Dict[Any, Any]: 52 | """ 53 | Overwrite this function in super class 54 | """ 55 | pass 56 | 57 | 58 | @ray.remote 59 | class RFRActor(ActorCls): 60 | """ 61 | An actor model to train and score the calfornia house data using Random Forest Regressor 62 | """ 63 | def __init__(self, configs): 64 | super().__init__(configs) 65 | self.estimators = configs["n_estimators"] 66 | 67 | 68 | def train_and_evaluate_model(self) -> Dict[Any, Any]: 69 | """ 70 | Train the model and evaluate and report MSE 71 | """ 72 | 73 | self._prepare_data_and_model() 74 | self.model = RandomForestRegressor(n_estimators=self.estimators, random_state=42) 75 | 76 | print(f"Start training model {self.name} with estimators: {self.estimators} ...") 77 | 78 | start_time = time.time() 79 | self.model.fit(self.X_train, self.y_train) 80 | self.state = STATES[1] 81 | y_pred = self.model.predict(self.X_test) 82 | score = mean_squared_error(self.y_test, y_pred) 83 | self.state = STATES[2] 84 | 85 | end_time = time.time() 86 | print(f"End training model {self.name} with estimators: {self.estimators} took: {end_time - start_time:.2f} seconds") 87 | 88 | return { "state": self.get_state(), 89 | "name": self.get_name(), 90 | "estimators": self.estimators, 91 | "mse": round(score, 4), 92 | "time": round(end_time - start_time, 2)} 93 | 94 | 95 | @ray.remote 96 | class DTActor(ActorCls): 97 | """ 98 | An actor model to train and score the calfornia house data using Decision Tree Regressor 99 | """ 100 | def __init__(self, configs): 101 | 102 | super().__init__(configs) 103 | self.max_depth = configs["max_depth"] 104 | 105 | def train_and_evaluate_model(self) -> Dict[Any, Any]: 106 | """ 107 | Train the model and evaluate and report MSE 108 | """ 109 | 110 | self._prepare_data_and_model() 111 | self.model = DecisionTreeRegressor(max_depth=self.max_depth, random_state=42) 112 | 113 | print(f"Start training model {self.name} with max depth: { self.max_depth } ...") 114 | 115 | start_time = time.time() 116 | self.model.fit(self.X_train, self.y_train) 117 | self.state = STATES[1] 118 | y_pred = self.model.predict(self.X_test) 119 | score = mean_squared_error(self.y_test, y_pred) 120 | self.state = STATES[2] 121 | 122 | end_time = time.time() 123 | print(f"End training model {self.name} with max_depth tree: {self.max_depth} took: {end_time - start_time:.2f} seconds") 124 | 125 | return { "state": self.get_state(), 126 | "name": self.get_name(), 127 | "max_depth": self.max_depth, 128 | "mse": round(score, 4), 129 | "time": round(end_time - start_time, 2)} 130 | 131 | @ray.remote 132 | class XGBoostActor(ActorCls): 133 | """ 134 | An actor model to train and score the calfornia house data using XGBoost Regressor 135 | """ 136 | def __init__(self, configs): 137 | 138 | super().__init__(configs) 139 | 140 | self.max_depth = configs["max_depth"] 141 | self.estimators = configs["n_estimators"] 142 | self.colsample = configs["colsample_bytree"] 143 | self.eta = configs["eta"] 144 | self.lr = configs["lr"] 145 | 146 | def train_and_evaluate_model(self) -> Dict[Any, Any]: 147 | """ 148 | Train the model and evaluate and report MSE 149 | """ 150 | 151 | self._prepare_data_and_model() 152 | self.model = xgb.XGBRegressor(objective='reg:squarederror', 153 | colsample_bytree=self.colsample, 154 | eta=self.eta, 155 | learning_rate = self.lr, 156 | max_depth=self.max_depth, 157 | n_estimators=self.estimators, 158 | random_state=42) 159 | 160 | print(f"Start training model {self.name} with estimators: {self.estimators} and max depth: { self.max_depth } ...") 161 | start_time = time.time() 162 | self.model.fit(self.X_train, self.y_train) 163 | self.state = STATES[1] 164 | y_pred = self.model.predict(self.X_test) 165 | score = mean_squared_error(self.y_test, y_pred) 166 | self.state = STATES[2] 167 | 168 | end_time = time.time() 169 | print(f"End training model {self.name} with estimators: {self.estimators} and max depth: { self.max_depth } and took: {end_time - start_time:.2f}") 170 | 171 | return {"state": self.get_state(), 172 | "name": self.get_name(), 173 | "max_depth": self.max_depth, 174 | "mse": round(score, 4), 175 | "estimators": self.estimators, 176 | "time": round(end_time - start_time, 2)} 177 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | ray[default] 2 | ray[all] 3 | jupyter 4 | jupyterlab 5 | scikit-learn 6 | tune-sklearn 7 | xgboost 8 | xgboost-ray 9 | tqdm 10 | torch 11 | torchvision 12 | scipy 13 | torchinfo 14 | matplotlib 15 | -------------------------------------------------------------------------------- /retired/README.md: -------------------------------------------------------------------------------- 1 | # Introduction to Ray Ecosystem for Distributed Applications 2 | 3 | 4 | 5 | Welcome to the tutorial at PyCon US 2022 in Salt Lake City 6 | 7 | 8 | 9 | 10 | This is a gentle introduction to basic Ray programming patterns and APIs for distributing computing. In this tutorial, we will cover at least three basic Ray patterns and its respective Ray Core APIs. 11 | 12 | * Remote Stateless Ray Tasks 13 | * Remote Stateful Ray Actors 14 | * Remote ObectRefs as Futures 15 | 16 | Additionally, a brief introductino to two of the Ray native libraries: 17 | * Introduction to Ray Tune and Ray Serve 18 | 19 | By no means all the Ray patterns and APIs are covered here. We recommend that you follow the references for [advanced patterns and antipatterns](https://docs.ray.io/en/latest/ray-design-patterns/index.html) if you want to use Ray to write your own ML-based libraries or want to take existing Python single-process or single-node multi-core applications and covert them into distributed multi-core, multi-node processes on a Ray cluster. 20 | 21 | Knowing these Ray patterns and anti-patterns will guide you in writing effective and robust distributed applications using the Ray framework and its recommended usage of Ray APIs. 22 | 23 | Additoinaly, we'll briefly examine how to use Tune APIs to train 🚆 and tune 🎸 your model 🤖, followed by an introduction 24 | to Ray Serve for deploying and serving models. 25 | 26 | ### 🧑‍🎓Prerequisite knowledge ### 27 | 28 | Some prior experience with Python and Jupyter notebooks will be helpful, but we'll explain most details as we go if you haven't used notebooks before. Knowledge of basic machine learning concepts, including hyperparameters, model serving, and principles of distributed computing is helpful, 29 | but not required. 30 | 31 | All exercises can be done on your laptop 💻, preferably running a Linux or macOS 🍎, using all its cores. Because you won’t have access to Ray clusters, we have to run Ray locally and parallelize all your tasks on all your cores. 32 | 33 | Python 3.7+ is required on your laptop, and some minimal installation of quick python packages using conda and pip. 34 | 35 | ### 👩‍🏫 Instructions to get started 36 | 37 | We assume that you have a `conda` installed. 38 | 39 | 1. `conda create -n ray-core-tutorial python=3.8` 40 | 2. `conda activate ray-core-tutorial` 41 | 3. `git clone git@github.com:dmatrix/ray-core-tutorial.git` 42 | 4. `cd` to 43 | 5. `python3 -m pip install -r requirements.txt` 44 | 6. `python3 -m ipykernel install` 45 | 7. `jupyter lab` 46 | 47 | If you are using **Apple M1 laptop** 🍎 follow the following instructions: 48 | 49 | 1. `conda create -n ray-core-tutorial python=3.8` 50 | 2. `conda activate ray-core-tutorial` 51 | 3. `conda install grpcio` 52 | 4. `python3 -m pip install -r requirements.txt` 53 | 5. `python3 -m ipykernel install` 54 | 6. `conda install jupyterlab` 55 | 7. `jupyter lab` 56 | 57 | Let's have 😜 fun with Ray @ PyCon US 2022! 58 | 59 | Thank you 🙏, 60 | 61 | Jules 62 | -------------------------------------------------------------------------------- /retired/data/file_1.txt: -------------------------------------------------------------------------------- 1 | 0, 48, 72, 75, 54, 89, 84, 68, 9, 38 2 | 3, 40, 73, 58, 10, 35, 96, 6, 65, 33 3 | 55, 67, 12, 97, 52, 73, 7, 76, 39, 50 4 | 59, 34, 20, 40, 92, 55, 11, 39, 93, 38 5 | 89, 89, 37, 52, 48, 86, 49, 3, 19, 50 6 | 84, 37, 68, 11, 20, 36, 46, 61, 52, 77 7 | 70, 90, 56, 55, 49, 76, 94, 28, 32, 23 8 | 5, 44, 92, 15, 53, 63, 87, 75, 61, 25 9 | 51, 58, 29, 30, 93, 94, 52, 72, 80, 27 10 | 1, 28, 82, 35, 89, 36, 10, 84, 85, 65 11 | -------------------------------------------------------------------------------- /retired/data/file_2.txt: -------------------------------------------------------------------------------- 1 | 101, 31, 83,124, 41, 73, 0,121, 14, 98 2 | 137, 3, 77, 38,117, 79,104, 96, 62,117 3 | 99, 92,139, 29, 59, 30,116, 30, 74, 12 4 | 130,105,145,124, 39, 50, 66, 9,126, 24 5 | 32, 33, 34, 90, 43,140,136,149,140, 22 6 | 14, 8,138,101,136, 60, 41,110, 92,105 7 | 44, 76,104, 6,121,135, 41,132,131, 26 8 | 1, 1,112, 45,146, 29, 44,104, 75,122 9 | 132, 63, 70,109, 49, 75, 33, 36, 38,105 10 | 131, 71, 51, 79,109,146, 71, 27, 65,126 11 | -------------------------------------------------------------------------------- /retired/ex_00_ray_tutorial_overview.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Ray Tutorial Basic Core APIs - Overview\n", 8 | "\n", 9 | "© 2021-2022, Anyscale. All Rights Reserved\n", 10 | "\n", 11 | "\n", 12 | "\n", 13 | "## About This Tutorial\n", 14 | "\n", 15 | "In this tutorial, we'll cover the basic Ray Core APIs and its fundamental patterns. This is an introductory material, covering three basic distributed Ray core APIs patterns:\n", 16 | "\n", 17 | " * Remote Functions as Tasks\n", 18 | " * Remote Objects as Futures\n", 19 | " * Remote Classes as stateful Actors\n", 20 | " * A quick introduction to Ray Tune and Ray Serve\n", 21 | " \n", 22 | " \n", 23 | "There are other advance [Ray Patterns and Anti-patterns](https://docs.ray.io/en/latest/ray-design-patterns/index.html), which are not covered in this tutorial. Mainly applicable when writing more complex distributed applications, we recommend reading them to equip yourself to use Ray APIs more effectively.\n", 24 | "\n", 25 | "Additionally, we also introduce [XGBoost-Ray](https://github.com/ray-project/xgboost_ray), a drop-in replacement for XGBoost that allows you to do distributed HPO.\n", 26 | "\n", 27 | "\n", 28 | "See the instructions in the [README](./README.md) for setting up your environment to use this tutorial." 29 | ] 30 | }, 31 | { 32 | "cell_type": "markdown", 33 | "metadata": {}, 34 | "source": [ 35 | "| | Lesson | Description |\n", 36 | "| :-- | :----- | :---------- |\n", 37 | "| | **Module 1** | **Focus on Ray Core API Patterns and Ray CLI** |\n", 38 | "| 00 | [Ray Tutorial Overview](ex_00_ray_tutorial_overview) | Overview of this tutorial. |\n", 39 | "| 01 | [Ray Remote Functions ](ex_01_remote_funcs.ipynb) |The Remote Function as StateLess Tasks Pattern. |\n", 40 | "| 02 | [Ray Remote Objects](ex_02_remote_objs.ipynb) |The Remote Objects as Futures Pattern. |\n", 41 | "| 03 | [Ray Remote Classes](ex_03_remote_classes.ipynb) |The Remote Classes as Stateful Actors Pattern |\n", 42 | "| 04 | [Ray API Calls Tour](ex_04_exploring_ray_api_calls.ipynb) |A look at common Ray API calls |\n", 43 | "| 05 | [Running Ray Clusters](ex_05_running_ray_clusters.ipynb) | Ray Clusters from CLI |\n", 44 | "| | **Module 2** | **Brief introduction Ray XGBoost and Ray Tune for HPO** |\n", 45 | "| 06 | [Ray XGBoost and Ray Tune](ex_06_xgboost_train_tune.ipynb) | Ray Tune and XGBoost-Ray Drop-in replacement for Distributed HPO |\n", 46 | "| 07 | [Ray Tune and Scikit-learn](ex_07_ray_tune_scklearn.ipynb) | Ray Tune and Scikit-learn's TuneGridSearchCV Drop-in replacement for Distributed HPO |\n", 47 | "| | **Module 3** | **Brief introduction Ray Serve** |\n", 48 | "| 08 | [Ray Serve Model Serving Challenges](ex_08_model_serving_challenges.ipynb) | What are model serving challenges today |\n", 49 | "| 09 | [Ray Serve Accessing Deployments](ex_09_ray_serve_create_and_access_deployments.ipynb) | Multiple ways to access deployments |\n", 50 | "| 10 | [Ray Serve Example](ex_10_ray_serve_example.ipynb) | A Simple Ray Serve Example |\n", 51 | "| 11 | [Ray Serve Sentiment Analysis](ex_11_ray_serve_sentiment_tweets.ipynb) | Model composition model deployment pattern. A sentiment analysis model using HuggingFace 🤗 transformers |" 52 | ] 53 | } 54 | ], 55 | "metadata": { 56 | "kernelspec": { 57 | "display_name": "Python 3 (ipykernel)", 58 | "language": "python", 59 | "name": "python3" 60 | }, 61 | "language_info": { 62 | "codemirror_mode": { 63 | "name": "ipython", 64 | "version": 3 65 | }, 66 | "file_extension": ".py", 67 | "mimetype": "text/x-python", 68 | "name": "python", 69 | "nbconvert_exporter": "python", 70 | "pygments_lexer": "ipython3", 71 | "version": "3.10.6" 72 | } 73 | }, 74 | "nbformat": 4, 75 | "nbformat_minor": 4 76 | } 77 | -------------------------------------------------------------------------------- /retired/ex_02_remote_objs.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# A Guided Tour of Ray Core: Remote Objects\n", 8 | "\n", 9 | "© 2019-2022, Anyscale. All Rights Reserved\n" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "[*Remote Objects*](https://docs.ray.io/en/latest/walkthrough.html#objects-in-ray)\n", 17 | "implement a [*shared-memory object store*](https://en.wikipedia.org/wiki/Shared_memory) pattern.\n", 18 | "\n", 19 | "Objects are immutable and can be accessed from anywhere on the cluster, as they are stored in the cluster shared memory.\n", 20 | "\n", 21 | "\n", 22 | "\n", 23 | "In general, small objects are stored in their owner’s **in-process store** while large objects are stored in the **distributed object store**. This decision is meant to reduce the memory footprint and resolution time for each object. Note that in the latter case, a placeholder object is stored in the in-process store to indicate the object has been promoted to shared memory.\n", 24 | "\n", 25 | "In the case if there is no space in the shared-memory, objects are spilled over to disk. But the main point here is that\n", 26 | "shared-memory allows zero-copy to processes on the same worker node.\n", 27 | "\n", 28 | "\n", 29 | "\n", 30 | "---" 31 | ] 32 | }, 33 | { 34 | "cell_type": "markdown", 35 | "metadata": {}, 36 | "source": [ 37 | "## 2. Object references as Futures Pattern" 38 | ] 39 | }, 40 | { 41 | "cell_type": "markdown", 42 | "metadata": {}, 43 | "source": [ 44 | "First, let's start Ray…" 45 | ] 46 | }, 47 | { 48 | "cell_type": "code", 49 | "execution_count": 2, 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "RayContext(dashboard_url='127.0.0.1:8265', python_version='3.8.12', ray_version='2.0.0.dev0', ray_commit='{{RAY_COMMIT_SHA}}', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-04-25_11-16-09_358676_9733/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-04-25_11-16-09_358676_9733/sockets/raylet', 'webui_url': '127.0.0.1:8265', 'session_dir': '/tmp/ray/session_2022-04-25_11-16-09_358676_9733', 'metrics_export_port': 61683, 'gcs_address': '127.0.0.1:54020', 'address': '127.0.0.1:54020', 'node_id': '55ab335477cac25f044eaa76483abca11cad960309aab0b89cb5c221'})\n" 57 | ] 58 | } 59 | ], 60 | "source": [ 61 | "import logging\n", 62 | "from pprint import pprint\n", 63 | "import ray\n", 64 | "\n", 65 | "if ray.is_initialized:\n", 66 | " ray.shutdown()\n", 67 | "context = ray.init(logging_level=logging.ERROR)\n", 68 | "pprint(context)" 69 | ] 70 | }, 71 | { 72 | "cell_type": "code", 73 | "execution_count": 4, 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stdout", 78 | "output_type": "stream", 79 | "text": [ 80 | "Dashboard url: http://127.0.0.1:8265\n" 81 | ] 82 | } 83 | ], 84 | "source": [ 85 | "print(f\"Dashboard url: http://{context.address_info['webui_url']}\")" 86 | ] 87 | }, 88 | { 89 | "cell_type": "markdown", 90 | "metadata": {}, 91 | "source": [ 92 | "## Remote Objects example" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "metadata": {}, 98 | "source": [ 99 | "To start, we'll define a remote object..." 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 5, 105 | "metadata": {}, 106 | "outputs": [ 107 | { 108 | "name": "stdout", 109 | "output_type": "stream", 110 | "text": [ 111 | "CPU times: user 50.4 ms, sys: 18.8 ms, total: 69.2 ms\n", 112 | "Wall time: 88.6 ms\n" 113 | ] 114 | }, 115 | { 116 | "data": { 117 | "text/plain": [ 118 | "ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000001000000)" 119 | ] 120 | }, 121 | "execution_count": 5, 122 | "metadata": {}, 123 | "output_type": "execute_result" 124 | } 125 | ], 126 | "source": [ 127 | "%%time\n", 128 | "num_list = [23, 42, 93]\n", 129 | "\n", 130 | "# returns an objectRef\n", 131 | "obj_ref = ray.put(num_list)\n", 132 | "obj_ref" 133 | ] 134 | }, 135 | { 136 | "cell_type": "markdown", 137 | "metadata": {}, 138 | "source": [ 139 | "Then retrieve the value of this object reference. This follows an object resolution protocol.\n", 140 | "\n", 141 | "\n", 142 | "\n", 143 | "Small objects are resolved by copying them directly from the owner’s **in-process store**. For example, if the owner calls `ray.get`, the system looks up and deserializes the value from the local **in-process store**. If the owner submits a dependent task, it inlines the object by copying the value directly into the task description. Note that these objects are local to the owner process: if a borrower attempts to resolve the value, the object is promoted to shared memory, where it can be retrieved through the distributed object resolution protocol described next.\n", 144 | "\n", 145 | "Resolving a large object. The object `x` is initially created on Node 2, e.g., because the task that returned the value ran on that node. This shows the steps when the owner (the caller of the task) calls `ray.get`: \n", 146 | "\n", 147 | " 1) Lookup object’s locations at the owner. \n", 148 | " 2) Select a location and send a request for a copy of the object. \n", 149 | " 3) Receive the object.\n", 150 | "\n" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 6, 156 | "metadata": {}, 157 | "outputs": [ 158 | { 159 | "data": { 160 | "text/plain": [ 161 | "[23, 42, 93]" 162 | ] 163 | }, 164 | "execution_count": 6, 165 | "metadata": {}, 166 | "output_type": "execute_result" 167 | } 168 | ], 169 | "source": [ 170 | "val = ray.get(obj_ref)\n", 171 | "val" 172 | ] 173 | }, 174 | { 175 | "cell_type": "markdown", 176 | "metadata": {}, 177 | "source": [ 178 | "Let's combine use of a remote function with a remote object, to illustrate *composable futures*:" 179 | ] 180 | }, 181 | { 182 | "cell_type": "code", 183 | "execution_count": 7, 184 | "metadata": {}, 185 | "outputs": [], 186 | "source": [ 187 | "@ray.remote\n", 188 | "def my_function (num_list):\n", 189 | " return sum(num_list)" 190 | ] 191 | }, 192 | { 193 | "cell_type": "markdown", 194 | "metadata": {}, 195 | "source": [ 196 | "In other words, the remote function `myfunction()` will sum the list of integers in the remote object `num_list`:" 197 | ] 198 | }, 199 | { 200 | "cell_type": "code", 201 | "execution_count": 8, 202 | "metadata": {}, 203 | "outputs": [], 204 | "source": [ 205 | "calc_ref = my_function.remote(obj_ref)" 206 | ] 207 | }, 208 | { 209 | "cell_type": "code", 210 | "execution_count": 9, 211 | "metadata": {}, 212 | "outputs": [ 213 | { 214 | "data": { 215 | "text/plain": [ 216 | "158" 217 | ] 218 | }, 219 | "execution_count": 9, 220 | "metadata": {}, 221 | "output_type": "execute_result" 222 | } 223 | ], 224 | "source": [ 225 | "result = ray.get(calc_ref)\n", 226 | "result" 227 | ] 228 | }, 229 | { 230 | "cell_type": "markdown", 231 | "metadata": {}, 232 | "source": [ 233 | "You can gather the values of multiple object references in parallel using comprehension:\n", 234 | " 1. Each value is put in the object store and its `ObjRefID` is immediately returned\n", 235 | " 2. The comprehsion constructs a list of `ObjRefIDs` for each element in the loop\n", 236 | " 3. A final `get(list_obj_refs`) is invoked to fetch the list" 237 | ] 238 | }, 239 | { 240 | "cell_type": "code", 241 | "execution_count": 10, 242 | "metadata": {}, 243 | "outputs": [ 244 | { 245 | "data": { 246 | "text/plain": [ 247 | "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" 248 | ] 249 | }, 250 | "execution_count": 10, 251 | "metadata": {}, 252 | "output_type": "execute_result" 253 | } 254 | ], 255 | "source": [ 256 | "results = ray.get([ray.put(i) for i in range(10)])\n", 257 | "results" 258 | ] 259 | }, 260 | { 261 | "cell_type": "markdown", 262 | "metadata": {}, 263 | "source": [ 264 | "### What about long running tasks?\n", 265 | "\n", 266 | "Now let's set a timeout to return early from attempted access of a remote object that is blocking for too long..." 267 | ] 268 | }, 269 | { 270 | "cell_type": "code", 271 | "execution_count": 11, 272 | "metadata": {}, 273 | "outputs": [], 274 | "source": [ 275 | "import time\n", 276 | "\n", 277 | "@ray.remote\n", 278 | "def long_running_function ():\n", 279 | " time.sleep(10)\n", 280 | " return 42" 281 | ] 282 | }, 283 | { 284 | "cell_type": "markdown", 285 | "metadata": {}, 286 | "source": [ 287 | "You can control how long you want to wait for the task to finish" 288 | ] 289 | }, 290 | { 291 | "cell_type": "code", 292 | "execution_count": 12, 293 | "metadata": {}, 294 | "outputs": [ 295 | { 296 | "name": "stdout", 297 | "output_type": "stream", 298 | "text": [ 299 | "`get` timed out\n", 300 | "CPU times: user 32.2 ms, sys: 28.8 ms, total: 61 ms\n", 301 | "Wall time: 6.02 s\n" 302 | ] 303 | } 304 | ], 305 | "source": [ 306 | "%%time\n", 307 | "\n", 308 | "from ray.exceptions import GetTimeoutError\n", 309 | "\n", 310 | "obj_ref = long_running_function.remote()\n", 311 | "\n", 312 | "try:\n", 313 | " ray.get(obj_ref, timeout=6)\n", 314 | "except GetTimeoutError:\n", 315 | " print(\"`get` timed out\")" 316 | ] 317 | }, 318 | { 319 | "cell_type": "code", 320 | "execution_count": 19, 321 | "metadata": {}, 322 | "outputs": [], 323 | "source": [ 324 | "ray.shutdown()" 325 | ] 326 | }, 327 | { 328 | "cell_type": "markdown", 329 | "metadata": {}, 330 | "source": [ 331 | "### Exercises\n", 332 | "\n", 333 | "1. Send a list of object references returned by `ray.put(x)` \n", 334 | "2. Use comprehension to construct this list and send it to `my_function.remote(list_of_object_refs)` to return the sum of the list\n", 335 | "3. Create a python object, use `ray.put(pobj)` and `ray.get(pobj)`" 336 | ] 337 | }, 338 | { 339 | "cell_type": "markdown", 340 | "metadata": {}, 341 | "source": [ 342 | "### Homework\n", 343 | "\n", 344 | "1. Read references to get advanced deep dives" 345 | ] 346 | }, 347 | { 348 | "cell_type": "markdown", 349 | "metadata": {}, 350 | "source": [ 351 | "## References\n", 352 | "\n", 353 | " * [Ray Architecture Reference](https://docs.google.com/document/d/1lAy0Owi-vPz2jEqBSaHNQcy2IBSDEHyXNOQZlGuj93c/preview#)\n", 354 | " * [Ray Internals: A peek at ray,get](https://www.youtube.com/watch?v=a1kNnQu6vGw)\n", 355 | " * [Ray Internals: Object management with Ownership Model](https://www.anyscale.com/events/2021/06/22/ray-internals-object-management-with-the-ownership-model)\n", 356 | " * [Deep Dive into Ray scheduling Policies](https://www.anyscale.com/events/2021/06/23/a-deep-dive-into-rays-scheduling-policy)\n", 357 | " * [Redis in Ray: Past and future](https://www.anyscale.com/blog/redis-in-ray-past-and-future)\n", 358 | " * [StackOverFlow: How Ray Shares Data](https://stackoverflow.com/questions/58082023/how-exactly-does-ray-share-data-to-workers/71500979#71500979)\n", 359 | " " 360 | ] 361 | } 362 | ], 363 | "metadata": { 364 | "kernelspec": { 365 | "display_name": "Python 3 (ipykernel)", 366 | "language": "python", 367 | "name": "python3" 368 | }, 369 | "language_info": { 370 | "codemirror_mode": { 371 | "name": "ipython", 372 | "version": 3 373 | }, 374 | "file_extension": ".py", 375 | "mimetype": "text/x-python", 376 | "name": "python", 377 | "nbconvert_exporter": "python", 378 | "pygments_lexer": "ipython3", 379 | "version": "3.8.12" 380 | } 381 | }, 382 | "nbformat": 4, 383 | "nbformat_minor": 4 384 | } 385 | -------------------------------------------------------------------------------- /retired/ex_07_ray_tune_scklearn.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "50156943", 6 | "metadata": {}, 7 | "source": [ 8 | "# Ray Crash Course - Distributed HPO with Ray Tune's TuneGridSearchCV and Scikit-Learn\n", 9 | "\n", 10 | "© 2019-2022, Anyscale. All Rights Reserved\n", 11 | "\n", 12 | "This demo introduces **Ray tune's** key concepts using a classification example. Basically, there are three basic steps or Ray Tune pattern for you as a newcomer to get started with using Ray Tune. We'll use a drop-in replacement for normal Scikit-learn's `GridSearchCV` with distributed Ray Tune's `TuneGridSearchCV`.\n", 13 | "\n", 14 | "See also the [Understanding Hyperparameter Tuning](https://github.com/anyscale/academy/blob/main/ray-tune/02-Understanding-Hyperparameter-Tuning.ipynb) notebook and the [Tune documentation](http://tune.io), in particular, the [API reference](https://docs.ray.io/en/latest/tune/api_docs/overview.html). \n" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 22, 20 | "id": "eed803cc", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "# Import Tune's replacement\n", 25 | "from ray.tune.sklearn import TuneGridSearchCV\n", 26 | "\n", 27 | "# Other relevant imports\n", 28 | "from sklearn.model_selection import train_test_split\n", 29 | "\n", 30 | "# Use the stochastic gradient descent (SGD) classifier\n", 31 | "from sklearn.linear_model import SGDClassifier\n", 32 | "\n", 33 | "# import the classification dataset\n", 34 | "from sklearn.datasets import make_classification\n", 35 | "import numpy as np\n", 36 | "import time\n", 37 | "import logging\n", 38 | "import ray" 39 | ] 40 | }, 41 | { 42 | "cell_type": "code", 43 | "execution_count": 23, 44 | "id": "f93759e0", 45 | "metadata": {}, 46 | "outputs": [ 47 | { 48 | "name": "stderr", 49 | "output_type": "stream", 50 | "text": [ 51 | "2022-04-19 11:19:38,906\tINFO services.py:1460 -- View the Ray dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8265\u001b[39m\u001b[22m\n" 52 | ] 53 | } 54 | ], 55 | "source": [ 56 | "CONNECT_TO_ANYSCALE=False\n", 57 | "if ray.is_initialized:\n", 58 | " ray.shutdown()\n", 59 | " if CONNECT_TO_ANYSCALE:\n", 60 | " ray.init(\"anyscale://jsd-ray-core-tutorial\")\n", 61 | " else:\n", 62 | " ray.init()" 63 | ] 64 | }, 65 | { 66 | "cell_type": "markdown", 67 | "id": "d9fc8350", 68 | "metadata": {}, 69 | "source": [ 70 | "### Create Feature Set\n", 71 | "\n", 72 | " * 250K rows\n", 73 | " * 250 features\n", 74 | " * 2 classes" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": 24, 80 | "id": "13e7b4fc", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "def create_classification_data() -> (np.ndarray, np.ndarray):\n", 85 | " X, y = make_classification(\n", 86 | " n_samples=250000,\n", 87 | " n_features=250,\n", 88 | " n_informative=50,\n", 89 | " n_redundant=0,\n", 90 | " n_classes=2,\n", 91 | " class_sep=2.5)\n", 92 | " return X, y" 93 | ] 94 | }, 95 | { 96 | "cell_type": "markdown", 97 | "id": "f96c690a", 98 | "metadata": {}, 99 | "source": [ 100 | "### Create classification data and define parameter search space" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 25, 106 | "id": "a20ef947", 107 | "metadata": {}, 108 | "outputs": [], 109 | "source": [ 110 | "X, y = create_classification_data()\n", 111 | "# Split the dataset into train and test sets\n", 112 | "x_train, x_test, y_train, y_test = train_test_split(X, y, test_size=10000)\n", 113 | "\n", 114 | "# Example parameters grid to tune from SGDClassifier\n", 115 | "parameter_grid = {\"alpha\": [1e-4, 1e-1, 1], \"epsilon\": [0.01, 0.1]}" 116 | ] 117 | }, 118 | { 119 | "cell_type": "markdown", 120 | "id": "7c2a5ee5", 121 | "metadata": {}, 122 | "source": [ 123 | "## Use Ray's Scikit-learn drop-in replacement TuneGridSearchCV\n", 124 | "Use all cores on a Ray Cluster or local host to tune " 125 | ] 126 | }, 127 | { 128 | "cell_type": "code", 129 | "execution_count": 26, 130 | "id": "2e100cde", 131 | "metadata": {}, 132 | "outputs": [], 133 | "source": [ 134 | "# Now let's do with Tune's in-place replacement\n", 135 | "# Note: If early_stopping=True, TuneGridSearchCV will default to using Tune’s ASHAScheduler.\n", 136 | "tune_sklearn = TuneGridSearchCV(SGDClassifier(), \n", 137 | " parameter_grid,\n", 138 | " early_stopping=True,\n", 139 | " max_iters=30,\n", 140 | " n_jobs=12, # Use 40 cores if running on a cluster\n", 141 | " mode=\"min\",\n", 142 | " verbose=True)" 143 | ] 144 | }, 145 | { 146 | "cell_type": "code", 147 | "execution_count": 27, 148 | "id": "a74c1d1a", 149 | "metadata": {}, 150 | "outputs": [ 151 | { 152 | "data": { 153 | "text/html": [ 154 | "== Status ==
Current time: 2022-04-19 11:21:00 (running for 00:01:00.03)
Memory usage on this node: 14.4/32.0 GiB
Using AsyncHyperBand: num_stopped=4\n", 155 | "Bracket: Iter 16.000: -0.9791052083333334 | Iter 4.000: -0.9734739583333334 | Iter 1.000: -0.9747270833333332
Resources requested: 0/12 CPUs, 0/0 GPUs, 0.0/15.61 GiB heap, 0.0/2.0 GiB objects
Current best trial: 52e75_00003 with average_test_score=0.9806791666666668 and parameters={'early_stopping': True, 'early_stop_type': , 'groups': None, 'cv': StratifiedKFold(n_splits=5, random_state=None, shuffle=False), 'fit_params': {}, 'scoring': {'score': }, 'max_iters': 30, 'return_train_score': False, 'n_jobs': 1, 'metric_name': 'average_test_score', 'alpha': 0.0001, 'epsilon': 0.1}
Result logdir: /Users/jules/ray_results/_Trainable_2022-04-19_11-19-59
Number of trials: 6/6 (6 TERMINATED)

" 156 | ], 157 | "text/plain": [ 158 | "" 159 | ] 160 | }, 161 | "metadata": {}, 162 | "output_type": "display_data" 163 | }, 164 | { 165 | "name": "stderr", 166 | "output_type": "stream", 167 | "text": [ 168 | "2022-04-19 11:21:00,108\tINFO tune.py:702 -- Total run time: 60.15 seconds (60.03 seconds for the tuning loop).\n" 169 | ] 170 | }, 171 | { 172 | "name": "stdout", 173 | "output_type": "stream", 174 | "text": [ 175 | "CPU times: user 2.03 s, sys: 1.28 s, total: 3.31 s\n", 176 | "Wall time: 1min 1s\n" 177 | ] 178 | }, 179 | { 180 | "data": { 181 | "text/plain": [ 182 | "TuneGridSearchCV(early_stopping=True, estimator=SGDClassifier(), max_iters=30,\n", 183 | " mode='min', n_jobs=12,\n", 184 | " param_grid={'alpha': [0.0001, 0.1, 1], 'epsilon': [0.01, 0.1]},\n", 185 | " sk_n_jobs=1, verbose=True)" 186 | ] 187 | }, 188 | "execution_count": 27, 189 | "metadata": {}, 190 | "output_type": "execute_result" 191 | } 192 | ], 193 | "source": [ 194 | "%%time\n", 195 | "tune_sklearn.fit(x_train, y_train)" 196 | ] 197 | }, 198 | { 199 | "cell_type": "code", 200 | "execution_count": 29, 201 | "id": "116b90ee", 202 | "metadata": {}, 203 | "outputs": [ 204 | { 205 | "name": "stdout", 206 | "output_type": "stream", 207 | "text": [ 208 | "Ray Tune Scikit-learn TuneGridSearchCV Best params: {'alpha': 0.1, 'epsilon': 0.1}\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "print(f\"Ray Tune Scikit-learn TuneGridSearchCV Best params: {tune_sklearn.best_params}\")" 214 | ] 215 | }, 216 | { 217 | "cell_type": "code", 218 | "execution_count": 30, 219 | "id": "4214cf5d-ce55-4a79-a294-93523b1a636c", 220 | "metadata": {}, 221 | "outputs": [], 222 | "source": [ 223 | "ray.shutdown()" 224 | ] 225 | }, 226 | { 227 | "cell_type": "markdown", 228 | "id": "9d9517b3-c139-4cc8-84cd-12a1aa224385", 229 | "metadata": {}, 230 | "source": [ 231 | "### Homework\n", 232 | "\n", 233 | "1. Try some [Tune How-to guides](https://docs.ray.io/en/latest/tune/examples/index.html) " 234 | ] 235 | } 236 | ], 237 | "metadata": { 238 | "kernelspec": { 239 | "display_name": "Python 3 (ipykernel)", 240 | "language": "python", 241 | "name": "python3" 242 | }, 243 | "language_info": { 244 | "codemirror_mode": { 245 | "name": "ipython", 246 | "version": 3 247 | }, 248 | "file_extension": ".py", 249 | "mimetype": "text/x-python", 250 | "name": "python", 251 | "nbconvert_exporter": "python", 252 | "pygments_lexer": "ipython3", 253 | "version": "3.8.13" 254 | } 255 | }, 256 | "nbformat": 4, 257 | "nbformat_minor": 5 258 | } 259 | -------------------------------------------------------------------------------- /retired/ex_09_ray_serve_create_and_access_deployments.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "d6e4dfe1-144a-4142-b3a2-9cd5fc20ced5", 6 | "metadata": {}, 7 | "source": [ 8 | "# Ray Serve - Creating, Deploying and Accessing Deployments\n", 9 | "\n", 10 | "© 2019-2022, Anyscale. All Rights Reserved\n", 11 | "\n", 12 | "This brief tutorial shows how to create, deploy, and expose access to\n", 13 | "deployment models, using the simple Ray Serve deployment APIs.\n", 14 | "Once deployed, you can send requests to deployments via two methods:\n", 15 | "\n", 16 | " 1. ServerHandle API\n", 17 | " 2. HTTP\n", 18 | " \n", 19 | " " 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 1, 25 | "id": "6162fac5-4fa5-4553-9a21-8ac8dab4a4a2", 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import os\n", 30 | "from random import random\n", 31 | "\n", 32 | "import requests\n", 33 | "import starlette\n", 34 | "from starlette.requests import Request\n", 35 | "import ray\n", 36 | "from ray import serve" 37 | ] 38 | }, 39 | { 40 | "cell_type": "markdown", 41 | "id": "05706639-da47-4826-80b8-b8915ca25696", 42 | "metadata": {}, 43 | "source": [ 44 | "A simple example model stored in a pickled format at an accessible path\n", 45 | "that can be reloaded and deserialized into a model instance. Once deployed\n", 46 | "in Ray Serve, we can use it for prediction. The prediction is a fake condition,\n", 47 | "based on threshold of weight greater than 0.5." 48 | ] 49 | }, 50 | { 51 | "cell_type": "code", 52 | "execution_count": 2, 53 | "id": "0a6596d7-e3f1-42cb-97f2-70f76b57450b", 54 | "metadata": {}, 55 | "outputs": [], 56 | "source": [ 57 | "class Model:\n", 58 | " def __init__(self, path):\n", 59 | " self.path = path\n", 60 | "\n", 61 | " def predict(self, data):\n", 62 | " return random() + data if data > 0.5 else data" 63 | ] 64 | }, 65 | { 66 | "cell_type": "code", 67 | "execution_count": 3, 68 | "id": "96ab2dd9-bcd3-4756-ac04-d0771a7a5441", 69 | "metadata": {}, 70 | "outputs": [], 71 | "source": [ 72 | "@serve.deployment\n", 73 | "class Deployment:\n", 74 | " # Take in a path to load your desired model\n", 75 | " def __init__(self, path: str) -> None:\n", 76 | " self.path = path\n", 77 | " self.model = Model(path)\n", 78 | " # Get the pid on which this deployment is running on\n", 79 | " self.pid = os.getpid()\n", 80 | "\n", 81 | " # Deployments are callable. Here we simply return a prediction from\n", 82 | " # our request\n", 83 | " def __call__(self, starlette_request) -> str:\n", 84 | " # Request came via an HTTP\n", 85 | " if isinstance(starlette_request, starlette.requests.Request):\n", 86 | " data = starlette_request.query_params['data']\n", 87 | " else:\n", 88 | " # Request came via a ServerHandle API method call.\n", 89 | " data = starlette_request\n", 90 | " pred = self.model.predict(float(data))\n", 91 | " return f\"(pid: {self.pid}); path: {self.path}; data: {float(data):.3f}; prediction: {pred:.3f}\"" 92 | ] 93 | }, 94 | { 95 | "cell_type": "markdown", 96 | "id": "8ce34a8a-9fe0-4c02-bf83-9b6210b08e7f", 97 | "metadata": {}, 98 | "source": [ 99 | "Start a Ray Serve instance. This will automatically start or connect to an existing Ray cluster." 100 | ] 101 | }, 102 | { 103 | "cell_type": "code", 104 | "execution_count": 4, 105 | "id": "b86ad83f-19c9-4410-b635-955497ecc20f", 106 | "metadata": {}, 107 | "outputs": [ 108 | { 109 | "name": "stderr", 110 | "output_type": "stream", 111 | "text": [ 112 | "2022-04-19 11:28:32,906\tINFO services.py:1460 -- View the Ray dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8267\u001b[39m\u001b[22m\n", 113 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:28:36,828\tINFO checkpoint_path.py:15 -- Using RayInternalKVStore for controller checkpoint and recovery.\n", 114 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:28:36,933\tINFO http_state.py:106 -- Starting HTTP proxy with name 'SERVE_CONTROLLER_ACTOR:wJcaTj:SERVE_PROXY_ACTOR-node:127.0.0.1-0' on node 'node:127.0.0.1-0' listening on '127.0.0.1:8000'\n", 115 | "2022-04-19 11:28:38,370\tINFO api.py:797 -- Started Serve instance in namespace 'serve'.\n" 116 | ] 117 | }, 118 | { 119 | "data": { 120 | "text/plain": [ 121 | "" 122 | ] 123 | }, 124 | "execution_count": 4, 125 | "metadata": {}, 126 | "output_type": "execute_result" 127 | } 128 | ], 129 | "source": [ 130 | "serve.start()" 131 | ] 132 | }, 133 | { 134 | "cell_type": "markdown", 135 | "id": "5de7ed24-649a-403c-ad76-085cf33c4eed", 136 | "metadata": {}, 137 | "source": [ 138 | "Create two distinct deployments of the same class as two replicas. \n", 139 | "Associate each deployment with a unique 'name'.This name can be used as to fetch its respective serve handle.\n", 140 | "See code below for method 1." 141 | ] 142 | }, 143 | { 144 | "cell_type": "code", 145 | "execution_count": 5, 146 | "id": "ffd04a68-e299-4647-bb75-2abf6492c2f4", 147 | "metadata": {}, 148 | "outputs": [ 149 | { 150 | "name": "stderr", 151 | "output_type": "stream", 152 | "text": [ 153 | "2022-04-19 11:28:38,388\tINFO api.py:618 -- Updating deployment 'rep-1'. component=serve deployment=rep-1\n", 154 | "\u001b[2m\u001b[36m(HTTPProxyActor pid=3510)\u001b[0m INFO: Started server process [3510]\n", 155 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:28:38,426\tINFO deployment_state.py:1210 -- Adding 2 replicas to deployment 'rep-1'. component=serve deployment=rep-1\n", 156 | "2022-04-19 11:28:40,400\tINFO api.py:633 -- Deployment 'rep-1' is ready at `http://127.0.0.1:8000/rep-1`. component=serve deployment=rep-1\n", 157 | "2022-04-19 11:28:40,407\tINFO api.py:618 -- Updating deployment 'rep-2'. component=serve deployment=rep-2\n", 158 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:28:40,461\tINFO deployment_state.py:1210 -- Adding 2 replicas to deployment 'rep-2'. component=serve deployment=rep-2\n", 159 | "2022-04-19 11:28:42,417\tINFO api.py:633 -- Deployment 'rep-2' is ready at `http://127.0.0.1:8000/rep-2`. component=serve deployment=rep-2\n" 160 | ] 161 | } 162 | ], 163 | "source": [ 164 | "Deployment.options(name=\"rep-1\", num_replicas=2).deploy(\"/model/rep-1.pkl\")\n", 165 | "Deployment.options(name=\"rep-2\", num_replicas=2).deploy(\"/model/rep-2.pkl\")" 166 | ] 167 | }, 168 | { 169 | "cell_type": "markdown", 170 | "id": "1afacbbf-e3ad-4312-8d53-39ac90d81a2b", 171 | "metadata": {}, 172 | "source": [ 173 | "### Get the current list of deployment\n" 174 | ] 175 | }, 176 | { 177 | "cell_type": "code", 178 | "execution_count": 6, 179 | "id": "a1ebe3d9-5b11-4e39-81a3-e4fb44f98f7b", 180 | "metadata": {}, 181 | "outputs": [ 182 | { 183 | "name": "stdout", 184 | "output_type": "stream", 185 | "text": [ 186 | "{'rep-1': Deployment(name=rep-1,version=None,route_prefix=/rep-1), 'rep-2': Deployment(name=rep-2,version=None,route_prefix=/rep-2)}\n" 187 | ] 188 | } 189 | ], 190 | "source": [ 191 | "print(serve.list_deployments())" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "id": "3d5b149f-b36f-44d5-9fdf-e04d3162a9ed", 197 | "metadata": {}, 198 | "source": [ 199 | "### Method 1: Access each deployment using the ServerHandle API" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 7, 205 | "id": "4fb8c5a8-04e2-4c66-8854-795839bc0c26", 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "name": "stderr", 210 | "output_type": "stream", 211 | "text": [ 212 | "2022-04-19 11:28:46,570\tWARNING api.py:488 -- You are retrieving a sync handle inside an asyncio loop. Try getting client.get_handle(.., sync=False) to get better performance. Learn more at https://docs.ray.io/en/master/serve/http-servehandle.html#sync-and-async-handles\n", 213 | "2022-04-19 11:28:46,587\tWARNING api.py:488 -- You are retrieving a sync handle inside an asyncio loop. Try getting client.get_handle(.., sync=False) to get better performance. Learn more at https://docs.ray.io/en/master/serve/http-servehandle.html#sync-and-async-handles\n" 214 | ] 215 | }, 216 | { 217 | "name": "stdout", 218 | "output_type": "stream", 219 | "text": [ 220 | "handle name : rep-1\n", 221 | "prediction : (pid: 3537); path: /model/rep-1.pkl; data: 0.553; prediction: 1.232\n", 222 | "--\n", 223 | "handle name : rep-2\n", 224 | "prediction : (pid: 3540); path: /model/rep-2.pkl; data: 0.965; prediction: 1.644\n", 225 | "--\n", 226 | "handle name : rep-1\n", 227 | "prediction : (pid: 3536); path: /model/rep-1.pkl; data: 0.415; prediction: 0.415\n", 228 | "--\n", 229 | "handle name : rep-2\n", 230 | "prediction : (pid: 3541); path: /model/rep-2.pkl; data: 0.515; prediction: 1.194\n", 231 | "--\n" 232 | ] 233 | } 234 | ], 235 | "source": [ 236 | "for _ in range(2):\n", 237 | " for d_name in [\"rep-1\", \"rep-2\"]:\n", 238 | " # Get handle to the each deployment and invoke its method.\n", 239 | " # Which replica the request is dispatched to is determined\n", 240 | " # by the Router actor.\n", 241 | " handle = serve.get_deployment(d_name).get_handle()\n", 242 | " print(f\"handle name : {d_name}\")\n", 243 | " print(f\"prediction : {ray.get(handle.remote(random()))}\")\n", 244 | " print(\"-\" * 2)" 245 | ] 246 | }, 247 | { 248 | "cell_type": "markdown", 249 | "id": "e22863fa-7128-4b1f-853c-5a77723ff344", 250 | "metadata": {}, 251 | "source": [ 252 | "### Method 2: Access deployment via HTTP Request" 253 | ] 254 | }, 255 | { 256 | "cell_type": "code", 257 | "execution_count": 8, 258 | "id": "6d4bcce3-30b5-4baa-b67d-d6a575a30edb", 259 | "metadata": {}, 260 | "outputs": [ 261 | { 262 | "name": "stdout", 263 | "output_type": "stream", 264 | "text": [ 265 | "handle name : rep-1\n", 266 | "prediction : (pid: 3537); path: /model/rep-1.pkl; data: 0.643; prediction: 1.273\n", 267 | "handle name : rep-2\n", 268 | "prediction : (pid: 3540); path: /model/rep-2.pkl; data: 0.247; prediction: 0.247\n", 269 | "handle name : rep-1\n", 270 | "prediction : (pid: 3536); path: /model/rep-1.pkl; data: 0.938; prediction: 1.617\n", 271 | "handle name : rep-2\n", 272 | "prediction : (pid: 3541); path: /model/rep-2.pkl; data: 0.493; prediction: 0.493\n" 273 | ] 274 | } 275 | ], 276 | "source": [ 277 | "for _ in range(2):\n", 278 | " for d_name in [\"rep-1\", \"rep-2\"]:\n", 279 | " # Send HTTP request along with data payload\n", 280 | " url = f\"http://127.0.0.1:8000/{d_name}\"\n", 281 | " print(f\"handle name : {d_name}\")\n", 282 | " print(f\"prediction : {requests.get(url, params={'data': random()}).text}\")" 283 | ] 284 | }, 285 | { 286 | "cell_type": "code", 287 | "execution_count": 9, 288 | "id": "e87a6d90-805a-4b4a-a37c-70b4e0715589", 289 | "metadata": {}, 290 | "outputs": [ 291 | { 292 | "name": "stderr", 293 | "output_type": "stream", 294 | "text": [ 295 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:29:04,136\tINFO deployment_state.py:1236 -- Removing 2 replicas from deployment 'rep-1'. component=serve deployment=rep-1\n", 296 | "\u001b[2m\u001b[36m(ServeController pid=3502)\u001b[0m 2022-04-19 11:29:04,140\tINFO deployment_state.py:1236 -- Removing 2 replicas from deployment 'rep-2'. component=serve deployment=rep-2\n" 297 | ] 298 | } 299 | ], 300 | "source": [ 301 | "serve.shutdown()" 302 | ] 303 | }, 304 | { 305 | "cell_type": "markdown", 306 | "id": "3c1e4e92-2eb0-4a18-9ffa-c24893c929e4", 307 | "metadata": {}, 308 | "source": [ 309 | "### Exercises\n", 310 | "\n", 311 | "Here are some things you can try:\n", 312 | "\n", 313 | "1. For each method, send ten requests\n", 314 | "2. Increase number of replicas\n", 315 | "3. Do requests get sent to different replicas? (check the pids or the Ray Dashboard)" 316 | ] 317 | } 318 | ], 319 | "metadata": { 320 | "kernelspec": { 321 | "display_name": "Python 3 (ipykernel)", 322 | "language": "python", 323 | "name": "python3" 324 | }, 325 | "language_info": { 326 | "codemirror_mode": { 327 | "name": "ipython", 328 | "version": 3 329 | }, 330 | "file_extension": ".py", 331 | "mimetype": "text/x-python", 332 | "name": "python", 333 | "nbconvert_exporter": "python", 334 | "pygments_lexer": "ipython3", 335 | "version": "3.10.6" 336 | } 337 | }, 338 | "nbformat": 4, 339 | "nbformat_minor": 5 340 | } 341 | -------------------------------------------------------------------------------- /retired/ex_10_ray_serve_example.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "metadata": {}, 6 | "source": [ 7 | "# Ray Serve - Model Serving\n", 8 | "\n", 9 | "© 2019-2022, Anyscale. All Rights Reserved\n" 10 | ] 11 | }, 12 | { 13 | "cell_type": "markdown", 14 | "metadata": {}, 15 | "source": [ 16 | "Now we'll explore a short example for Ray Serve. This example is from the Ray Serve [scikit-learn example.](https://docs.ray.io/en/latest/serve/tutorials/sklearn.html)\n", 17 | "\n", 18 | "See also the Serve documentation's [mini-tutorials](https://docs.ray.io/en/latest/serve/tutorials/index.html) for using Serve with various frameworks.\n", 19 | "\n", 20 | "" 21 | ] 22 | }, 23 | { 24 | "cell_type": "code", 25 | "execution_count": 1, 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "import ray\n", 30 | "from ray import serve\n", 31 | "import requests # for making web requests\n", 32 | "import tempfile\n", 33 | "\n", 34 | "import os\n", 35 | "import pickle\n", 36 | "import json\n", 37 | "import numpy as np" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": 2, 43 | "metadata": {}, 44 | "outputs": [ 45 | { 46 | "name": "stderr", 47 | "output_type": "stream", 48 | "text": [ 49 | "2022-04-19 11:29:41,124\tINFO services.py:1460 -- View the Ray dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8268\u001b[39m\u001b[22m\n", 50 | "\u001b[2m\u001b[36m(ServeController pid=3675)\u001b[0m 2022-04-19 11:29:45,067\tINFO checkpoint_path.py:15 -- Using RayInternalKVStore for controller checkpoint and recovery.\n", 51 | "\u001b[2m\u001b[36m(ServeController pid=3675)\u001b[0m 2022-04-19 11:29:45,172\tINFO http_state.py:106 -- Starting HTTP proxy with name 'SERVE_CONTROLLER_ACTOR:BkVkza:SERVE_PROXY_ACTOR-node:127.0.0.1-0' on node 'node:127.0.0.1-0' listening on '127.0.0.1:8000'\n", 52 | "2022-04-19 11:29:46,505\tINFO api.py:797 -- Started Serve instance in namespace 'serve'.\n" 53 | ] 54 | }, 55 | { 56 | "data": { 57 | "text/plain": [ 58 | "" 59 | ] 60 | }, 61 | "execution_count": 2, 62 | "metadata": {}, 63 | "output_type": "execute_result" 64 | } 65 | ], 66 | "source": [ 67 | "serve.start()" 68 | ] 69 | }, 70 | { 71 | "cell_type": "markdown", 72 | "metadata": {}, 73 | "source": [ 74 | "## Create a Model to Serve \n", 75 | "\n", 76 | "We'll begin by training a classifier with the Iris data we used before, this time using [scikit-learn](https://scikit-learn.org/stable/). The details aren't too important for our purposes, except for the fact we'll save the trained model to disk for subsequent serving." 77 | ] 78 | }, 79 | { 80 | "cell_type": "code", 81 | "execution_count": 3, 82 | "metadata": {}, 83 | "outputs": [ 84 | { 85 | "name": "stderr", 86 | "output_type": "stream", 87 | "text": [ 88 | "\u001b[2m\u001b[36m(HTTPProxyActor pid=3677)\u001b[0m INFO: Started server process [3677]\n" 89 | ] 90 | } 91 | ], 92 | "source": [ 93 | "import sklearn\n", 94 | "from sklearn.datasets import load_iris\n", 95 | "from sklearn.ensemble import GradientBoostingClassifier\n", 96 | "from sklearn.metrics import mean_squared_error" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 4, 102 | "metadata": {}, 103 | "outputs": [], 104 | "source": [ 105 | "# Load data\n", 106 | "iris_dataset = load_iris()\n", 107 | "data, target, target_names = iris_dataset[\"data\"], iris_dataset[\n", 108 | " \"target\"], iris_dataset[\"target_names\"]" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 5, 114 | "metadata": {}, 115 | "outputs": [], 116 | "source": [ 117 | "# Instantiate model\n", 118 | "model = GradientBoostingClassifier()" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 6, 124 | "metadata": {}, 125 | "outputs": [], 126 | "source": [ 127 | "# Training and validation split\n", 128 | "data, target = sklearn.utils.shuffle(data, target)\n", 129 | "train_x, train_y = data[:100], target[:100]\n", 130 | "val_x, val_y = data[100:], target[100:]" 131 | ] 132 | }, 133 | { 134 | "cell_type": "code", 135 | "execution_count": 7, 136 | "metadata": {}, 137 | "outputs": [ 138 | { 139 | "name": "stdout", 140 | "output_type": "stream", 141 | "text": [ 142 | "MSE: 0.02\n" 143 | ] 144 | } 145 | ], 146 | "source": [ 147 | "# Train and evaluate models\n", 148 | "model.fit(train_x, train_y)\n", 149 | "print(\"MSE:\", mean_squared_error(model.predict(val_x), val_y))" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "metadata": { 155 | "tags": [] 156 | }, 157 | "source": [ 158 | "Save the model and label to file. This could also be S3 or other \"global\" place or fetched from the model regsitry." 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 8, 164 | "metadata": {}, 165 | "outputs": [], 166 | "source": [ 167 | "MODEL_PATH = os.path.join(tempfile.gettempdir(),\n", 168 | " \"iris_model_logistic_regression.pkl\")\n", 169 | "LABEL_PATH = os.path.join(tempfile.gettempdir(), \"iris_labels.json\")" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 9, 175 | "metadata": {}, 176 | "outputs": [], 177 | "source": [ 178 | "with open(MODEL_PATH, \"wb\") as f:\n", 179 | " pickle.dump(model, f)\n", 180 | "with open(LABEL_PATH, \"w\") as f:\n", 181 | " json.dump(target_names.tolist(), f)" 182 | ] 183 | }, 184 | { 185 | "cell_type": "markdown", 186 | "metadata": {}, 187 | "source": [ 188 | "## Create a Deployment and Serve It\n", 189 | "\n", 190 | "Next, we define a servable model by instantiating a class and defining the `__call__` method that Ray Serve will use. " 191 | ] 192 | }, 193 | { 194 | "cell_type": "code", 195 | "execution_count": 10, 196 | "metadata": {}, 197 | "outputs": [], 198 | "source": [ 199 | "@serve.deployment(route_prefix=\"/regressor\", num_replicas=2)\n", 200 | "class BoostingModel:\n", 201 | " def __init__(self):\n", 202 | " with open(MODEL_PATH, \"rb\") as f:\n", 203 | " self.model = pickle.load(f)\n", 204 | " with open(LABEL_PATH) as f:\n", 205 | " self.label_list = json.load(f)\n", 206 | "\n", 207 | " # async allows us to have this call concurrently \n", 208 | " async def __call__(self, starlette_request):\n", 209 | " payload = await starlette_request.json()\n", 210 | " print(\"Worker: received starlette request with data\", payload)\n", 211 | "\n", 212 | " input_vector = [\n", 213 | " payload[\"sepal length\"],\n", 214 | " payload[\"sepal width\"],\n", 215 | " payload[\"petal length\"],\n", 216 | " payload[\"petal width\"],\n", 217 | " ]\n", 218 | " prediction = self.model.predict([input_vector])[0]\n", 219 | " human_name = self.label_list[prediction]\n", 220 | " return {\"result\": human_name}" 221 | ] 222 | }, 223 | { 224 | "cell_type": "markdown", 225 | "metadata": {}, 226 | "source": [ 227 | "## Deploy the model" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 11, 233 | "metadata": {}, 234 | "outputs": [ 235 | { 236 | "name": "stderr", 237 | "output_type": "stream", 238 | "text": [ 239 | "2022-04-19 11:29:48,245\tINFO api.py:618 -- Updating deployment 'BoostingModel'. component=serve deployment=BoostingModel\n", 240 | "\u001b[2m\u001b[36m(ServeController pid=3675)\u001b[0m 2022-04-19 11:29:48,348\tINFO deployment_state.py:1210 -- Adding 2 replicas to deployment 'BoostingModel'. component=serve deployment=BoostingModel\n", 241 | "2022-04-19 11:29:50,252\tINFO api.py:633 -- Deployment 'BoostingModel' is ready at `http://127.0.0.1:8000/regressor`. component=serve deployment=BoostingModel\n" 242 | ] 243 | } 244 | ], 245 | "source": [ 246 | "BoostingModel.deploy()" 247 | ] 248 | }, 249 | { 250 | "cell_type": "markdown", 251 | "metadata": {}, 252 | "source": [ 253 | "## Score the model\n", 254 | "Internally, Serve stores the model as a Ray actor and routes traffic to it as the endpoint is queried, in this case over HTTP. \n", 255 | "\n", 256 | "Now let’s query the endpoint to see results." 257 | ] 258 | }, 259 | { 260 | "cell_type": "code", 261 | "execution_count": 12, 262 | "metadata": {}, 263 | "outputs": [], 264 | "source": [ 265 | "sample_request_input = {\n", 266 | " \"sepal length\": 1.2,\n", 267 | " \"sepal width\": 1.0,\n", 268 | " \"petal length\": 1.1,\n", 269 | " \"petal width\": 0.9,\n", 270 | "}" 271 | ] 272 | }, 273 | { 274 | "cell_type": "markdown", 275 | "metadata": {}, 276 | "source": [ 277 | "We can now send HTTP requests to our route `route_prefix=/regressor` at the default port 8000" 278 | ] 279 | }, 280 | { 281 | "cell_type": "code", 282 | "execution_count": 13, 283 | "metadata": {}, 284 | "outputs": [ 285 | { 286 | "name": "stdout", 287 | "output_type": "stream", 288 | "text": [ 289 | "{\n", 290 | " \"result\": \"versicolor\"\n", 291 | "}\n", 292 | "\u001b[2m\u001b[36m(BoostingModel pid=3679)\u001b[0m Worker: received starlette request with data {'sepal length': 1.2, 'sepal width': 1.0, 'petal length': 1.1, 'petal width': 0.9}\n" 293 | ] 294 | } 295 | ], 296 | "source": [ 297 | "response = requests.get(\n", 298 | " \"http://localhost:8000/regressor\", json=sample_request_input)\n", 299 | "print(response.text)" 300 | ] 301 | }, 302 | { 303 | "cell_type": "code", 304 | "execution_count": 14, 305 | "metadata": {}, 306 | "outputs": [ 307 | { 308 | "name": "stdout", 309 | "output_type": "stream", 310 | "text": [ 311 | "{'result': 'versicolor'}\n", 312 | "\u001b[2m\u001b[36m(BoostingModel pid=3680)\u001b[0m Worker: received starlette request with data {'sepal length': 1.2, 'sepal width': 1.0, 'petal length': 1.1, 'petal width': 0.9}\n" 313 | ] 314 | } 315 | ], 316 | "source": [ 317 | "response = requests.get(\"http://localhost:8000/regressor\", json=sample_request_input).json()\n", 318 | "print(response)" 319 | ] 320 | }, 321 | { 322 | "cell_type": "code", 323 | "execution_count": 15, 324 | "metadata": {}, 325 | "outputs": [ 326 | { 327 | "name": "stdout", 328 | "output_type": "stream", 329 | "text": [ 330 | "deployments: {'BoostingModel': Deployment(name=BoostingModel,version=None,route_prefix=/regressor)}\n" 331 | ] 332 | } 333 | ], 334 | "source": [ 335 | "deployments = serve.list_deployments()\n", 336 | "print(f'deployments: {deployments}')" 337 | ] 338 | }, 339 | { 340 | "cell_type": "code", 341 | "execution_count": 16, 342 | "metadata": {}, 343 | "outputs": [ 344 | { 345 | "name": "stderr", 346 | "output_type": "stream", 347 | "text": [ 348 | "\u001b[2m\u001b[36m(ServeController pid=3675)\u001b[0m 2022-04-19 11:30:02,607\tINFO deployment_state.py:1236 -- Removing 2 replicas from deployment 'BoostingModel'. component=serve deployment=BoostingModel\n" 349 | ] 350 | } 351 | ], 352 | "source": [ 353 | "serve.shutdown() " 354 | ] 355 | }, 356 | { 357 | "cell_type": "markdown", 358 | "metadata": {}, 359 | "source": [ 360 | "### Exercise\n", 361 | "\n", 362 | "Here are some things you can try:\n", 363 | "\n", 364 | "1. Send more input requests." 365 | ] 366 | }, 367 | { 368 | "cell_type": "markdown", 369 | "metadata": {}, 370 | "source": [ 371 | "## Homework\n", 372 | "1. Add a small model of your own and deploy it on Ray Serve\n", 373 | "2. Send some requests\n", 374 | "3. Try some [mini tutorials](https://docs.ray.io/en/latest/serve/tutorials/index.html) for other Frameworks" 375 | ] 376 | } 377 | ], 378 | "metadata": { 379 | "kernelspec": { 380 | "display_name": "Python 3 (ipykernel)", 381 | "language": "python", 382 | "name": "python3" 383 | }, 384 | "language_info": { 385 | "codemirror_mode": { 386 | "name": "ipython", 387 | "version": 3 388 | }, 389 | "file_extension": ".py", 390 | "mimetype": "text/x-python", 391 | "name": "python", 392 | "nbconvert_exporter": "python", 393 | "pygments_lexer": "ipython3", 394 | "version": "3.8.13" 395 | } 396 | }, 397 | "nbformat": 4, 398 | "nbformat_minor": 4 399 | } 400 | -------------------------------------------------------------------------------- /retired/highly_parallel.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "515dffba", 6 | "metadata": {}, 7 | "source": [ 8 | "# Using Ray for Highly Parallelizable Tasks\n", 9 | "\n", 10 | "While Ray can be used for very complex parallelization tasks,\n", 11 | "often we just want to do something simple in parallel.\n", 12 | "For example, we may have 100,000 time series to process with exactly the same algorithm,\n", 13 | "and each one takes a minute of processing.\n", 14 | "\n", 15 | "Clearly running it on a single processor is prohibitive: this would take 70 days.\n", 16 | "Even if we managed to use 8 processors on a single machine,\n", 17 | "that would bring it down to 9 days. But if we can use 8 machines, each with 16 cores,\n", 18 | "it can be done in about 12 hours.\n", 19 | "\n", 20 | "How can we use Ray for these types of task? \n", 21 | "\n", 22 | "## Let's try to compute the value of PI\n", 23 | "\n", 24 | "\n", 25 | "We take the simple example of computing the digits of pi using the [monte carlo](https://www.geeksforgeeks.org/estimating-value-pi-using-monte-carlo/) approach.\n", 26 | "The algorithm is simple: generate random x and y, and if ``x^2 + y^2 < 1``, it's\n", 27 | "inside the circle, we count as in. This actually turns out to be pi/4\n", 28 | "(remembering your high school math).\n", 29 | "\n", 30 | "\n", 31 | "\n", 32 | "The following code (and this notebook) assumes you have already set up your Ray cluster and that you are running on the head node. For more details on how to set up a Ray cluster please see the [Ray Cluster Quickstart Guide](https://docs.ray.io/en/master/cluster/quickstart.html). \n", 33 | "\n", 34 | "📖 [Back to Table of Contents](../ex_00_tutorial_overview.ipynb)
\n", 35 | "\n" 36 | ] 37 | }, 38 | { 39 | "cell_type": "code", 40 | "execution_count": 1, 41 | "id": "8e3e7c4f", 42 | "metadata": {}, 43 | "outputs": [], 44 | "source": [ 45 | "import os\n", 46 | "import time\n", 47 | "import logging\n", 48 | "from pprint import pprint\n", 49 | "\n", 50 | "import ray\n", 51 | "import random\n", 52 | "import math\n", 53 | "from fractions import Fraction" 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 2, 59 | "id": "92d2461b", 60 | "metadata": { 61 | "scrolled": true, 62 | "tags": [ 63 | "remove-output" 64 | ] 65 | }, 66 | "outputs": [ 67 | { 68 | "data": { 69 | "text/html": [ 70 | "
\n", 71 | "
\n", 72 | "

Ray

\n", 73 | " \n", 74 | " \n", 75 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | " \n", 97 | " \n", 98 | " \n", 99 | " \n", 100 | " \n", 101 | " \n", 102 | " \n", 103 | " \n", 104 | " \n", 105 | " \n", 106 | "\n", 107 | "\n", 108 | "
Python version:3.8.13
Ray version: 2.0.0
Dashboard:http://127.0.0.1:8267
\n", 109 | "
\n", 110 | "
\n" 111 | ], 112 | "text/plain": [ 113 | "RayContext(dashboard_url='127.0.0.1:8267', python_version='3.8.13', ray_version='2.0.0', ray_commit='cba26cc83f6b5b8a2ff166594a65cb74c0ec8740', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-10-17_14-33-48_731138_54123/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-10-17_14-33-48_731138_54123/sockets/raylet', 'webui_url': '127.0.0.1:8267', 'session_dir': '/tmp/ray/session_2022-10-17_14-33-48_731138_54123', 'metrics_export_port': 65012, 'gcs_address': '127.0.0.1:51188', 'address': '127.0.0.1:51188', 'dashboard_agent_listen_port': 52365, 'node_id': 'df1374dcddc8edce6f16014936802ab68042513e8fb82564d317abc4'})" 114 | ] 115 | }, 116 | "execution_count": 2, 117 | "metadata": {}, 118 | "output_type": "execute_result" 119 | } 120 | ], 121 | "source": [ 122 | "if ray.is_initialized:\n", 123 | " ray.shutdown()\n", 124 | "ray.init(logging_level=logging.ERROR)" 125 | ] 126 | }, 127 | { 128 | "cell_type": "markdown", 129 | "id": "b96f2eb9", 130 | "metadata": {}, 131 | "source": [ 132 | "We use the ``@ray.remote`` decorator to create a Ray task.\n", 133 | "A task is like a function, except the result is returned asynchronously.\n", 134 | "\n", 135 | "It also may not run on the local machine, it may run elsewhere in the cluster.\n", 136 | "This way you can run multiple tasks in parallel,\n", 137 | "beyond the limit of the number of processors you can have in a single machine." 138 | ] 139 | }, 140 | { 141 | "cell_type": "code", 142 | "execution_count": 3, 143 | "id": "ece9887c", 144 | "metadata": {}, 145 | "outputs": [], 146 | "source": [ 147 | "@ray.remote\n", 148 | "def pi4_sample(sample_count):\n", 149 | " \"\"\"pi4_sample runs sample_count experiments, and returns the \n", 150 | " fraction of time it was inside the circle. \n", 151 | " \"\"\"\n", 152 | " in_count = 0\n", 153 | " for i in range(sample_count):\n", 154 | " x = random.random()\n", 155 | " y = random.random()\n", 156 | " if x*x + y*y <= 1:\n", 157 | " in_count += 1\n", 158 | " return Fraction(in_count, sample_count)\n" 159 | ] 160 | }, 161 | { 162 | "cell_type": "markdown", 163 | "id": "05bf8675", 164 | "metadata": {}, 165 | "source": [ 166 | "To get the result of a future, we use `ray.get()` which \n", 167 | "blocks until the result is complete. " 168 | ] 169 | }, 170 | { 171 | "cell_type": "code", 172 | "execution_count": 4, 173 | "id": "9d9a3509", 174 | "metadata": {}, 175 | "outputs": [ 176 | { 177 | "name": "stdout", 178 | "output_type": "stream", 179 | "text": [ 180 | "Running 1000000 tests took 0.22035717964172363 seconds\n" 181 | ] 182 | } 183 | ], 184 | "source": [ 185 | "SAMPLE_COUNT = 1000 * 1000\n", 186 | "start = time.time() \n", 187 | "future = pi4_sample.remote(sample_count = SAMPLE_COUNT)\n", 188 | "pi4 = ray.get(future)\n", 189 | "end = time.time()\n", 190 | "dur = end - start\n", 191 | "print(f'Running {SAMPLE_COUNT} tests took {dur} seconds')" 192 | ] 193 | }, 194 | { 195 | "cell_type": "markdown", 196 | "id": "cc17429d", 197 | "metadata": {}, 198 | "source": [ 199 | "Now let's see how good our approximation is." 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 5, 205 | "id": "42d4c464", 206 | "metadata": {}, 207 | "outputs": [], 208 | "source": [ 209 | "pi = pi4 * 4" 210 | ] 211 | }, 212 | { 213 | "cell_type": "code", 214 | "execution_count": 6, 215 | "id": "4009bee0", 216 | "metadata": {}, 217 | "outputs": [ 218 | { 219 | "name": "stdout", 220 | "output_type": "stream", 221 | "text": [ 222 | " Our computed PI: 3.138556; real PI: 3.141592653589793\n" 223 | ] 224 | } 225 | ], 226 | "source": [ 227 | "print(f\" Our computed PI: {float(pi)}; real PI: {math.pi}\")" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 7, 233 | "id": "d19155d6", 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "data": { 238 | "text/plain": [ 239 | "0.0009675320720080237" 240 | ] 241 | }, 242 | "execution_count": 7, 243 | "metadata": {}, 244 | "output_type": "execute_result" 245 | } 246 | ], 247 | "source": [ 248 | "abs(pi-math.pi)/pi" 249 | ] 250 | }, 251 | { 252 | "cell_type": "markdown", 253 | "id": "ddb3b095", 254 | "metadata": {}, 255 | "source": [ 256 | "Meh. A little off -- that's barely 4 decimal places.\n", 257 | "Why don't we do it a 100,000 times as much? Let's do 100 billion!\n", 258 | "`FULL_SAMPLE_COUNT = 100 * 1000 * 1000 * 1000 # 100 billion samples!` may take a while. \n", 259 | "\n", 260 | "Let's try with `1, 2 and 3b` and observe each value.\n" 261 | ] 262 | }, 263 | { 264 | "cell_type": "code", 265 | "execution_count": 8, 266 | "id": "b7b9cff9", 267 | "metadata": {}, 268 | "outputs": [ 269 | { 270 | "name": "stdout", 271 | "output_type": "stream", 272 | "text": [ 273 | "Doing 1000 batches\n", 274 | "Running 1000000 tests took 21.831931114196777 seconds\n" 275 | ] 276 | } 277 | ], 278 | "source": [ 279 | "FULL_SAMPLE_COUNT = 1 * 1000 * 1000 * 1000 # 1 billion samples! \n", 280 | "start = time.time()\n", 281 | "BATCHES = int(FULL_SAMPLE_COUNT / SAMPLE_COUNT)\n", 282 | "print(f'Doing {BATCHES} batches')\n", 283 | "results = []\n", 284 | "for _ in range(BATCHES):\n", 285 | " results.append(pi4_sample.remote(sample_count = SAMPLE_COUNT))\n", 286 | "output = ray.get(results)\n", 287 | "end = time.time()\n", 288 | "dur = end - start\n", 289 | "print(f'Running {SAMPLE_COUNT} tests took {dur} seconds')" 290 | ] 291 | }, 292 | { 293 | "cell_type": "markdown", 294 | "id": "94264de4", 295 | "metadata": {}, 296 | "source": [ 297 | "Notice that in the above, we generated a list with 100,000 futures.\n", 298 | "Now all we do is have to do is wait for the result.\n", 299 | "\n", 300 | "Depending on your ray cluster's size, this might take a few minutes.\n", 301 | "But to give you some idea, if we were to do it on a single machine,\n", 302 | "when we ran this, it took 0.4 seconds.\n", 303 | "\n", 304 | "On a single core, that means we're looking at 0.4 * 100000 = about 11 hours. \n", 305 | "\n", 306 | "So now, rather than just a single core working on this, we have all our cores working on the task together (depending on the number cores on each worker node). " 307 | ] 308 | }, 309 | { 310 | "cell_type": "code", 311 | "execution_count": 9, 312 | "id": "76eba02d", 313 | "metadata": {}, 314 | "outputs": [], 315 | "source": [ 316 | "pi = sum(output)*4/len(output)" 317 | ] 318 | }, 319 | { 320 | "cell_type": "code", 321 | "execution_count": 10, 322 | "id": "ede2bd8c", 323 | "metadata": {}, 324 | "outputs": [ 325 | { 326 | "data": { 327 | "text/plain": [ 328 | "3.14151778" 329 | ] 330 | }, 331 | "execution_count": 10, 332 | "metadata": {}, 333 | "output_type": "execute_result" 334 | } 335 | ], 336 | "source": [ 337 | "float(pi)" 338 | ] 339 | }, 340 | { 341 | "cell_type": "code", 342 | "execution_count": 11, 343 | "id": "bb62cb27", 344 | "metadata": {}, 345 | "outputs": [ 346 | { 347 | "data": { 348 | "text/plain": [ 349 | "2.3833571870816713e-05" 350 | ] 351 | }, 352 | "execution_count": 11, 353 | "metadata": {}, 354 | "output_type": "execute_result" 355 | } 356 | ], 357 | "source": [ 358 | "float(abs(pi-math.pi)/pi)" 359 | ] 360 | }, 361 | { 362 | "cell_type": "markdown", 363 | "id": "30d12e50", 364 | "metadata": {}, 365 | "source": [ 366 | "Not bad at all -- we're off by a millionth. " 367 | ] 368 | }, 369 | { 370 | "cell_type": "markdown", 371 | "id": "f038accd-21f7-499a-a2aa-40aad28a03db", 372 | "metadata": {}, 373 | "source": [ 374 | "### Reference\n", 375 | "\n", 376 | "1. [How to scale Python multiprocessing to a cluster with one line of code](https://medium.com/distributed-computing-with-ray/how-to-scale-python-multiprocessing-to-a-cluster-with-one-line-of-code-d19f242f60ff) \n", 377 | "2. [Using Ray for Highly Parallelizable Tasks](https://docs.ray.io/en/master/ray-core/examples/highly_parallel.html)" 378 | ] 379 | }, 380 | { 381 | "cell_type": "markdown", 382 | "id": "ea4b1786-3940-41e5-8460-190b51c6837c", 383 | "metadata": {}, 384 | "source": [ 385 | "📖 [Back to Table of Contents](../ex_00_tutorial_overview.ipynb)
" 386 | ] 387 | } 388 | ], 389 | "metadata": { 390 | "celltoolbar": "Tags", 391 | "kernelspec": { 392 | "display_name": "Python 3 (ipykernel)", 393 | "language": "python", 394 | "name": "python3" 395 | }, 396 | "language_info": { 397 | "codemirror_mode": { 398 | "name": "ipython", 399 | "version": 3 400 | }, 401 | "file_extension": ".py", 402 | "mimetype": "text/x-python", 403 | "name": "python", 404 | "nbconvert_exporter": "python", 405 | "pygments_lexer": "ipython3", 406 | "version": "3.8.13" 407 | } 408 | }, 409 | "nbformat": 4, 410 | "nbformat_minor": 5 411 | } 412 | -------------------------------------------------------------------------------- /retired/images/PatternsMLProduction.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/PatternsMLProduction.png -------------------------------------------------------------------------------- /retired/images/PyCon2022_Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/PyCon2022_Logo.png -------------------------------------------------------------------------------- /retired/images/actor_and_workders.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/actor_and_workders.png -------------------------------------------------------------------------------- /retired/images/architecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/architecture.png -------------------------------------------------------------------------------- /retired/images/func_class_deployment.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/func_class_deployment.png -------------------------------------------------------------------------------- /retired/images/func_class_deployment_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/func_class_deployment_2.png -------------------------------------------------------------------------------- /retired/images/object_resolution.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/object_resolution.png -------------------------------------------------------------------------------- /retired/images/ray-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray-logo.png -------------------------------------------------------------------------------- /retired/images/ray_basic_patterns.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_basic_patterns.png -------------------------------------------------------------------------------- /retired/images/ray_cluster.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_cluster.png -------------------------------------------------------------------------------- /retired/images/ray_serve_deployment_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_serve_deployment_workflow.png -------------------------------------------------------------------------------- /retired/images/ray_serve_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_serve_overview.png -------------------------------------------------------------------------------- /retired/images/ray_tune_dist_hpo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_tune_dist_hpo.png -------------------------------------------------------------------------------- /retired/images/ray_worker_actor_1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_worker_actor_1.png -------------------------------------------------------------------------------- /retired/images/ray_worker_actor_2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/ray_worker_actor_2.png -------------------------------------------------------------------------------- /retired/images/sentiment_analysis.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/sentiment_analysis.jpeg -------------------------------------------------------------------------------- /retired/images/shared_memory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/shared_memory.png -------------------------------------------------------------------------------- /retired/images/shared_memory_plasma_store.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/shared_memory_plasma_store.png -------------------------------------------------------------------------------- /retired/images/task_api_add_array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/task_api_add_array.png -------------------------------------------------------------------------------- /retired/images/task_dependencies_graphs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/task_dependencies_graphs.png -------------------------------------------------------------------------------- /retired/images/task_ownership.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/task_ownership.png -------------------------------------------------------------------------------- /retired/images/tune_flow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/images/tune_flow.png -------------------------------------------------------------------------------- /retired/requirements.txt: -------------------------------------------------------------------------------- 1 | ray[default] 2 | ray[all] 3 | jupyter 4 | jupyterlab 5 | scikit-learn 6 | tune-sklearn 7 | xgboost 8 | xgboost-ray 9 | tqdm 10 | -------------------------------------------------------------------------------- /retired/slides/pyconus2022/pyconsus_slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/slides/pyconus2022/pyconsus_slides.pdf -------------------------------------------------------------------------------- /retired/slides/weekly-demos/presentation_slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/retired/slides/weekly-demos/presentation_slides.pdf -------------------------------------------------------------------------------- /retired/solutions/ex_01_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 23, 6 | "id": "db1a7d02-4378-4184-bd08-d29c7ae8d8ab", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import math\n", 11 | "import numpy as np\n", 12 | "import logging\n", 13 | "from pprint import pprint\n", 14 | "from typing import List\n", 15 | "import ray" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 25, 21 | "id": "b4ef2d84-4903-429e-96c8-a24210ceec34", 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "@ray.remote\n", 26 | "def slow_method(num: int, dims=10) -> List[np.array]:\n", 27 | " dot_products = []\n", 28 | " for _ in range(num):\n", 29 | " # Create a dims x dims matrix\n", 30 | " x = np.random.rand(dims, dims)\n", 31 | " y = np.random.rand(dims, dims)\n", 32 | " # Create a dot product of itself\n", 33 | " dot_products.append(np.dot(x, y))\n", 34 | " return dot_products" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 26, 40 | "id": "68e43170-0260-4f7b-91df-4433770145a2", 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "name": "stdout", 45 | "output_type": "stream", 46 | "text": [ 47 | "RayContext(dashboard_url='127.0.0.1:8268', python_version='3.8.12', ray_version='2.0.0.dev0', ray_commit='{{RAY_COMMIT_SHA}}', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-04-12_20-08-32_792180_75624/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-04-12_20-08-32_792180_75624/sockets/raylet', 'webui_url': '127.0.0.1:8268', 'session_dir': '/tmp/ray/session_2022-04-12_20-08-32_792180_75624', 'metrics_export_port': 63718, 'gcs_address': '127.0.0.1:61890', 'address': '127.0.0.1:61890', 'node_id': '1033c5f86275a3c136446d6f0167df4252ea2bcb1d8e624731d0683f'})\n" 48 | ] 49 | } 50 | ], 51 | "source": [ 52 | "if ray.is_initialized:\n", 53 | " ray.shutdown()\n", 54 | "context = ray.init(logging_level=logging.ERROR)\n", 55 | "pprint(context)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": 27, 61 | "id": "129f5c00-b71b-45d8-84ca-25b20ff1acc9", 62 | "metadata": {}, 63 | "outputs": [ 64 | { 65 | "name": "stdout", 66 | "output_type": "stream", 67 | "text": [ 68 | "Dashboard url: http://127.0.0.1:8268\n" 69 | ] 70 | } 71 | ], 72 | "source": [ 73 | "print(f\"Dashboard url: http://{context.address_info['webui_url']}\")" 74 | ] 75 | }, 76 | { 77 | "cell_type": "code", 78 | "execution_count": 28, 79 | "id": "f0677e24-0b30-4831-b348-2ce8147576a8", 80 | "metadata": {}, 81 | "outputs": [ 82 | { 83 | "name": "stdout", 84 | "output_type": "stream", 85 | "text": [ 86 | "[[], [array([[1254.75103542, 1263.44977541, 1256.79552605, ..., 1251.38925517,\n", 87 | " 1258.10691228, 1237.67227246],\n", 88 | " [1237.92135129, 1248.11874766, 1236.71503673, ..., 1235.37863989,\n", 89 | " 1235.01688414, 1231.5786307 ],\n", 90 | " [1242.27804496, 1254.59332238, 1258.56410395, ..., 1246.62994948,\n", 91 | " 1241.00129843, 1241.24246935],\n", 92 | " ...,\n", 93 | " [1250.81478881, 1250.75241626, 1254.67709941, ..., 1244.01105921,\n", 94 | " 1250.12977093, 1239.15314547],\n", 95 | " [1245.00991477, 1252.6484969 , 1245.82516085, ..., 1255.55391927,\n", 96 | " 1251.72045296, 1231.17696796],\n", 97 | " [1244.15661435, 1248.75711711, 1247.04815943, ..., 1252.2612197 ,\n", 98 | " 1245.36061293, 1235.65127128]])], [array([[1265.35240908, 1238.13943797, 1260.19433701, ..., 1265.17357757,\n", 99 | " 1262.3145888 , 1247.57462287],\n", 100 | " [1263.34239507, 1230.35471309, 1255.92384506, ..., 1264.9407517 ,\n", 101 | " 1261.53195768, 1241.07058822],\n", 102 | " [1275.19653919, 1238.78333325, 1261.78395583, ..., 1274.36457588,\n", 103 | " 1273.23073055, 1264.31254573],\n", 104 | " ...,\n", 105 | " [1262.18269999, 1241.02203374, 1258.06179841, ..., 1273.52002282,\n", 106 | " 1275.60597867, 1255.66137056],\n", 107 | " [1260.24715633, 1237.42101072, 1255.94604066, ..., 1266.85549001,\n", 108 | " 1277.48965259, 1256.82917975],\n", 109 | " [1265.67630923, 1235.74650174, 1259.83534502, ..., 1262.03897968,\n", 110 | " 1270.29616271, 1261.32694735]]), array([[1229.22745053, 1223.14769839, 1226.62380873, ..., 1232.92573491,\n", 111 | " 1230.67784599, 1219.97675392],\n", 112 | " [1251.1204877 , 1244.92510887, 1258.29774573, ..., 1254.08602637,\n", 113 | " 1256.86271346, 1251.21357563],\n", 114 | " [1245.68406865, 1252.6341574 , 1252.64961243, ..., 1259.25714296,\n", 115 | " 1256.8215843 , 1253.42041772],\n", 116 | " ...,\n", 117 | " [1254.04990316, 1260.925521 , 1260.89802286, ..., 1254.57811256,\n", 118 | " 1268.28828872, 1251.87933366],\n", 119 | " [1249.85371277, 1258.6821871 , 1257.09990314, ..., 1257.83661774,\n", 120 | " 1253.46782481, 1251.61481129],\n", 121 | " [1235.28848775, 1254.88757995, 1249.20652425, ..., 1247.39977529,\n", 122 | " 1252.95532462, 1246.12850938]])], [array([[1237.81034962, 1236.3385498 , 1260.74293891, ..., 1247.40732119,\n", 123 | " 1255.49019786, 1234.65009041],\n", 124 | " [1229.37379583, 1235.26155242, 1260.19967546, ..., 1239.2240627 ,\n", 125 | " 1268.39229399, 1262.30085441],\n", 126 | " [1212.49330006, 1217.49904466, 1252.89927136, ..., 1229.37853306,\n", 127 | " 1244.18497365, 1240.58291376],\n", 128 | " ...,\n", 129 | " [1232.89610271, 1231.5279054 , 1250.30524808, ..., 1248.25738456,\n", 130 | " 1241.57469297, 1248.94433893],\n", 131 | " [1220.17199049, 1235.9151727 , 1242.50240349, ..., 1239.02820681,\n", 132 | " 1254.14673226, 1241.34966448],\n", 133 | " [1232.70927738, 1242.47638247, 1260.38366213, ..., 1247.5327304 ,\n", 134 | " 1253.41925295, 1238.355636 ]]), array([[1226.83538398, 1250.75981244, 1236.05107696, ..., 1247.02754745,\n", 135 | " 1231.40437062, 1244.92371953],\n", 136 | " [1258.40937714, 1272.51123025, 1252.82918253, ..., 1265.44719233,\n", 137 | " 1232.02523032, 1251.31376379],\n", 138 | " [1244.96201065, 1265.26518192, 1237.18163867, ..., 1263.00783624,\n", 139 | " 1225.16045311, 1240.55973161],\n", 140 | " ...,\n", 141 | " [1250.79654007, 1276.72216528, 1245.1201029 , ..., 1278.40894695,\n", 142 | " 1249.17225512, 1256.80243346],\n", 143 | " [1249.05748426, 1270.8616783 , 1255.78497467, ..., 1261.89291726,\n", 144 | " 1260.94865019, 1259.39621987],\n", 145 | " [1257.59053357, 1281.27654146, 1249.44735705, ..., 1268.83853469,\n", 146 | " 1257.13456118, 1262.57993856]]), array([[1229.93581334, 1238.68192502, 1258.34499983, ..., 1236.90671756,\n", 147 | " 1241.18945337, 1242.23559996],\n", 148 | " [1222.70315868, 1239.62586206, 1246.9114698 , ..., 1235.11449119,\n", 149 | " 1251.9476294 , 1252.99861152],\n", 150 | " [1228.61173964, 1242.01697267, 1244.62706445, ..., 1240.98082085,\n", 151 | " 1249.6202127 , 1252.63595589],\n", 152 | " ...,\n", 153 | " [1219.70236538, 1238.10175191, 1239.6367322 , ..., 1240.79453755,\n", 154 | " 1251.8095576 , 1227.20463102],\n", 155 | " [1222.6439827 , 1234.86651298, 1257.16306799, ..., 1242.23659314,\n", 156 | " 1242.93048293, 1235.69568988],\n", 157 | " [1222.7861455 , 1241.36383562, 1260.20458976, ..., 1251.66379778,\n", 158 | " 1248.41131281, 1255.0706066 ]])], [array([[1251.62149823, 1249.00449431, 1263.50573124, ..., 1244.21264619,\n", 159 | " 1239.0390246 , 1236.7053611 ],\n", 160 | " [1245.57837855, 1244.79946345, 1258.69885503, ..., 1242.04519921,\n", 161 | " 1239.13914121, 1239.61493992],\n", 162 | " [1237.61988111, 1245.1007778 , 1261.93142022, ..., 1242.47064323,\n", 163 | " 1231.03100103, 1248.55148331],\n", 164 | " ...,\n", 165 | " [1243.81735599, 1249.94747723, 1260.21732 , ..., 1241.40081698,\n", 166 | " 1248.69097974, 1240.13447004],\n", 167 | " [1274.35303655, 1267.98866352, 1288.06443476, ..., 1276.00058952,\n", 168 | " 1265.98152515, 1276.42032526],\n", 169 | " [1267.90271971, 1258.74824338, 1268.90363668, ..., 1255.85413356,\n", 170 | " 1258.59144098, 1252.36828253]]), array([[1261.28822632, 1240.3416569 , 1261.89785174, ..., 1245.55910059,\n", 171 | " 1251.55885247, 1244.89516814],\n", 172 | " [1276.89438538, 1250.09239874, 1247.12087337, ..., 1279.07614608,\n", 173 | " 1262.62822709, 1262.19425857],\n", 174 | " [1258.71420113, 1243.24408893, 1247.10858221, ..., 1233.31830443,\n", 175 | " 1243.51915924, 1239.52189042],\n", 176 | " ...,\n", 177 | " [1259.39530084, 1231.71529341, 1240.88957964, ..., 1249.01096399,\n", 178 | " 1246.92752435, 1241.15721588],\n", 179 | " [1262.34023928, 1231.08472549, 1261.56620681, ..., 1235.93251394,\n", 180 | " 1252.83088782, 1249.20858187],\n", 181 | " [1239.05052215, 1235.18820102, 1246.50081769, ..., 1247.07231645,\n", 182 | " 1235.82086781, 1247.3694316 ]]), array([[1260.14709582, 1267.18327581, 1246.71322653, ..., 1276.29536668,\n", 183 | " 1280.28962292, 1260.27166042],\n", 184 | " [1257.431675 , 1255.95930161, 1237.45866183, ..., 1265.49199407,\n", 185 | " 1277.46097709, 1238.87044391],\n", 186 | " [1233.02760804, 1252.14700152, 1217.54964254, ..., 1261.39846519,\n", 187 | " 1268.21000353, 1233.58291328],\n", 188 | " ...,\n", 189 | " [1251.06464901, 1269.66823614, 1236.9061452 , ..., 1262.40237022,\n", 190 | " 1282.56864003, 1240.21228025],\n", 191 | " [1259.17476265, 1249.66548547, 1238.30847497, ..., 1259.49753889,\n", 192 | " 1287.22700655, 1237.32907333],\n", 193 | " [1231.35980777, 1249.22499092, 1238.91392114, ..., 1260.06259597,\n", 194 | " 1270.66406536, 1241.72662082]]), array([[1251.14599571, 1273.99782941, 1232.81183743, ..., 1268.77330799,\n", 195 | " 1243.84342157, 1262.55539061],\n", 196 | " [1272.78271412, 1282.10416011, 1256.05547558, ..., 1270.3257063 ,\n", 197 | " 1239.15703595, 1275.77170289],\n", 198 | " [1250.69543524, 1258.36706144, 1226.5822154 , ..., 1258.85378613,\n", 199 | " 1233.21871841, 1256.89631698],\n", 200 | " ...,\n", 201 | " [1229.19730682, 1255.42920859, 1224.8175728 , ..., 1250.75877617,\n", 202 | " 1206.08590619, 1242.75695134],\n", 203 | " [1243.29506617, 1253.09376636, 1228.78481077, ..., 1258.79886183,\n", 204 | " 1227.27296674, 1247.31968855],\n", 205 | " [1260.09013668, 1267.79411824, 1237.81273515, ..., 1257.9850232 ,\n", 206 | " 1236.73389906, 1267.71889264]])]]\n", 207 | "CPU times: user 151 ms, sys: 71.1 ms, total: 222 ms\n", 208 | "Wall time: 22.2 s\n" 209 | ] 210 | } 211 | ], 212 | "source": [ 213 | "%%time\n", 214 | "results = [slow_method.remote(i, 5_000) for i in range(5)]\n", 215 | "print(ray.get(results))" 216 | ] 217 | }, 218 | { 219 | "cell_type": "code", 220 | "execution_count": 29, 221 | "id": "8482dfac-4043-410c-a75d-1588cfd893c7", 222 | "metadata": {}, 223 | "outputs": [], 224 | "source": [ 225 | "ray.shutdown()" 226 | ] 227 | } 228 | ], 229 | "metadata": { 230 | "kernelspec": { 231 | "display_name": "Python 3 (ipykernel)", 232 | "language": "python", 233 | "name": "python3" 234 | }, 235 | "language_info": { 236 | "codemirror_mode": { 237 | "name": "ipython", 238 | "version": 3 239 | }, 240 | "file_extension": ".py", 241 | "mimetype": "text/x-python", 242 | "name": "python", 243 | "nbconvert_exporter": "python", 244 | "pygments_lexer": "ipython3", 245 | "version": "3.8.12" 246 | } 247 | }, 248 | "nbformat": 4, 249 | "nbformat_minor": 5 250 | } 251 | -------------------------------------------------------------------------------- /retired/solutions/ex_02_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "1be69dae-83d9-43d1-81e7-41c26b683ce3", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "RayContext(dashboard_url='127.0.0.1:8267', python_version='3.8.12', ray_version='2.0.0.dev0', ray_commit='{{RAY_COMMIT_SHA}}', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445/sockets/raylet', 'webui_url': '127.0.0.1:8267', 'session_dir': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445', 'metrics_export_port': 65382, 'gcs_address': '127.0.0.1:64612', 'address': '127.0.0.1:64612', 'node_id': '7232289a9b1cd1025eca11df0e1122621f1a665ea41c197b9d9d35c0'})\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "import logging\n", 19 | "from pprint import pprint\n", 20 | "import ray\n", 21 | "\n", 22 | "if ray.is_initialized:\n", 23 | " ray.shutdown()\n", 24 | "context = ray.init(logging_level=logging.ERROR)\n", 25 | "pprint(context)" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "id": "0084eab3-f381-430d-a750-74b4a8e434f8", 32 | "metadata": {}, 33 | "outputs": [ 34 | { 35 | "name": "stdout", 36 | "output_type": "stream", 37 | "text": [ 38 | "Dashboard url: http://127.0.0.1:8267\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "print(f\"Dashboard url: http://{context.address_info['webui_url']}\")" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 6, 49 | "id": "8110da95-01b2-4b73-ba13-f7cfea166329", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "@ray.remote\n", 54 | "def my_function (num_list):\n", 55 | " return sum(num_list)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "id": "7bf709bd-217c-4553-80c1-042c7dddb34f", 61 | "metadata": {}, 62 | "source": [ 63 | "### Method 1\n", 64 | "\n", 65 | "Without comprehension" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 11, 71 | "id": "7618f6df-f2b6-4286-9dae-fe24497caae0", 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "data": { 76 | "text/plain": [ 77 | "[ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000015000000),\n", 78 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000016000000),\n", 79 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000017000000),\n", 80 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000018000000),\n", 81 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000019000000),\n", 82 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001a000000),\n", 83 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001b000000),\n", 84 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001c000000),\n", 85 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001d000000),\n", 86 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001e000000)]" 87 | ] 88 | }, 89 | "execution_count": 11, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "obj_refs = [ray.put(i) for i in range(10)]\n", 96 | "obj_refs" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 13, 102 | "id": "6835d594-e51d-4da8-a53c-01d7d6c39e44", 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" 109 | ] 110 | }, 111 | "execution_count": 13, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "values = ray.get(obj_refs)\n", 118 | "values" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 14, 124 | "id": "4a48c181-a6c8-41fe-bf71-78ceaaff2fef", 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "sum_obj_ref = my_function.remote(values)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 15, 134 | "id": "3ec83055-db03-4651-959b-26d116905ea5", 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "45" 141 | ] 142 | }, 143 | "execution_count": 15, 144 | "metadata": {}, 145 | "output_type": "execute_result" 146 | } 147 | ], 148 | "source": [ 149 | "ray.get(sum_obj_ref)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "id": "85096fa6-8cea-4b50-aff7-3b4857df64ec", 155 | "metadata": {}, 156 | "source": [ 157 | "### Method 2\n", 158 | "Using comprehension" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 16, 164 | "id": "33f2a5d0-ea98-4997-9cde-c3cf7d801f85", 165 | "metadata": {}, 166 | "outputs": [ 167 | { 168 | "data": { 169 | "text/plain": [ 170 | "45" 171 | ] 172 | }, 173 | "execution_count": 16, 174 | "metadata": {}, 175 | "output_type": "execute_result" 176 | } 177 | ], 178 | "source": [ 179 | "ray.get(my_function.remote(ray.get([ray.put(i) for i in range(10)])))" 180 | ] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 3 (ipykernel)", 186 | "language": "python", 187 | "name": "python3" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 3 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython3", 199 | "version": "3.8.12" 200 | } 201 | }, 202 | "nbformat": 4, 203 | "nbformat_minor": 5 204 | } 205 | -------------------------------------------------------------------------------- /retired/solutions/ex_03_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 2, 6 | "id": "e425ccaf-273b-4126-8b2b-147dbbd8aa8a", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import logging\n", 11 | "import time\n", 12 | "from pprint import pprint\n", 13 | "import ray\n", 14 | "import random\n", 15 | "from random import randint\n", 16 | "import numpy as np" 17 | ] 18 | }, 19 | { 20 | "cell_type": "code", 21 | "execution_count": 3, 22 | "id": "2f61c376-5c2f-4f26-bd57-1b50624dadbd", 23 | "metadata": {}, 24 | "outputs": [], 25 | "source": [ 26 | "from collections import defaultdict\n", 27 | "@ray.remote\n", 28 | "class LoggingActor(object):\n", 29 | " def __init__(self):\n", 30 | " self.logs = defaultdict(list)\n", 31 | " \n", 32 | " def log(self, index, message):\n", 33 | " self.logs[index].append(message)\n", 34 | " \n", 35 | " def get_logs(self):\n", 36 | " return dict(self.logs)\n", 37 | " \n", 38 | "@ray.remote\n", 39 | "def run_experiment(experiment_index, logging_actor):\n", 40 | " for i in range(60):\n", 41 | " time.sleep(1)\n", 42 | " # Push a logging message to the actor.\n", 43 | " logging_actor.log.remote(experiment_index, 'On iteration {}'.format(i)) " 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 4, 49 | "id": "566abe08-0af6-42e7-ba57-532166f4d0ce", 50 | "metadata": {}, 51 | "outputs": [ 52 | { 53 | "name": "stdout", 54 | "output_type": "stream", 55 | "text": [ 56 | "RayContext(dashboard_url='127.0.0.1:8265', python_version='3.8.12', ray_version='2.0.0.dev0', ray_commit='{{RAY_COMMIT_SHA}}', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-04-12_17-36-24_075332_63548/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-04-12_17-36-24_075332_63548/sockets/raylet', 'webui_url': '127.0.0.1:8265', 'session_dir': '/tmp/ray/session_2022-04-12_17-36-24_075332_63548', 'metrics_export_port': 55021, 'gcs_address': '127.0.0.1:63184', 'address': '127.0.0.1:63184', 'node_id': '7b1932893136ebdc505d7c89756e53dd861ab5a948a3831d403f163e'})\n" 57 | ] 58 | } 59 | ], 60 | "source": [ 61 | "if ray.is_initialized:\n", 62 | " ray.shutdown()\n", 63 | "context = ray.init(logging_level=logging.ERROR)\n", 64 | "pprint(context)" 65 | ] 66 | }, 67 | { 68 | "cell_type": "code", 69 | "execution_count": 5, 70 | "id": "cd2a3f51-92a1-4ff9-8d22-56b47ebf69da", 71 | "metadata": {}, 72 | "outputs": [], 73 | "source": [ 74 | "logging_actor = LoggingActor.remote()\n", 75 | "experiment_ids = []\n", 76 | "for i in range(3):\n", 77 | " experiment_ids.append(run_experiment.remote(i, logging_actor))" 78 | ] 79 | }, 80 | { 81 | "cell_type": "code", 82 | "execution_count": 7, 83 | "id": "3ed4fc03-339f-4866-a3ef-dfd12051d078", 84 | "metadata": {}, 85 | "outputs": [ 86 | { 87 | "name": "stdout", 88 | "output_type": "stream", 89 | "text": [ 90 | "{0: ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8', 'On iteration 9', 'On iteration 10', 'On iteration 11', 'On iteration 12', 'On iteration 13', 'On iteration 14', 'On iteration 15', 'On iteration 16', 'On iteration 17', 'On iteration 18', 'On iteration 19', 'On iteration 20', 'On iteration 21', 'On iteration 22', 'On iteration 23', 'On iteration 24', 'On iteration 25', 'On iteration 26', 'On iteration 27', 'On iteration 28', 'On iteration 29', 'On iteration 30', 'On iteration 31', 'On iteration 32', 'On iteration 33'], 2: ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8', 'On iteration 9', 'On iteration 10', 'On iteration 11', 'On iteration 12', 'On iteration 13', 'On iteration 14', 'On iteration 15', 'On iteration 16', 'On iteration 17', 'On iteration 18', 'On iteration 19', 'On iteration 20', 'On iteration 21', 'On iteration 22', 'On iteration 23', 'On iteration 24', 'On iteration 25', 'On iteration 26', 'On iteration 27', 'On iteration 28', 'On iteration 29', 'On iteration 30', 'On iteration 31', 'On iteration 32', 'On iteration 33'], 1: ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8', 'On iteration 9', 'On iteration 10', 'On iteration 11', 'On iteration 12', 'On iteration 13', 'On iteration 14', 'On iteration 15', 'On iteration 16', 'On iteration 17', 'On iteration 18', 'On iteration 19', 'On iteration 20', 'On iteration 21', 'On iteration 22', 'On iteration 23', 'On iteration 24', 'On iteration 25', 'On iteration 26', 'On iteration 27', 'On iteration 28', 'On iteration 29', 'On iteration 30', 'On iteration 31', 'On iteration 32', 'On iteration 33']}\n" 91 | ] 92 | } 93 | ], 94 | "source": [ 95 | "logs = logging_actor.get_logs.remote()\n", 96 | "print(ray.get(logs))" 97 | ] 98 | } 99 | ], 100 | "metadata": { 101 | "kernelspec": { 102 | "display_name": "Python 3 (ipykernel)", 103 | "language": "python", 104 | "name": "python3" 105 | }, 106 | "language_info": { 107 | "codemirror_mode": { 108 | "name": "ipython", 109 | "version": 3 110 | }, 111 | "file_extension": ".py", 112 | "mimetype": "text/x-python", 113 | "name": "python", 114 | "nbconvert_exporter": "python", 115 | "pygments_lexer": "ipython3", 116 | "version": "3.8.12" 117 | } 118 | }, 119 | "nbformat": 4, 120 | "nbformat_minor": 5 121 | } 122 | -------------------------------------------------------------------------------- /retired/solutions/ex_08_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "fbd3efe1-5183-4393-91ad-566aaddee191", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import ray\n", 11 | "from ray import serve\n", 12 | "import random\n", 13 | "\n", 14 | "import requests" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "id": "f717b5af-3ee4-4d35-96ea-5ea8be26470e", 21 | "metadata": {}, 22 | "outputs": [ 23 | { 24 | "name": "stderr", 25 | "output_type": "stream", 26 | "text": [ 27 | "2022-04-12 18:56:04,726\tINFO services.py:1460 -- View the Ray dashboard at \u001b[1m\u001b[32mhttp://127.0.0.1:8266\u001b[39m\u001b[22m\n", 28 | "\u001b[2m\u001b[36m(ServeController pid=71592)\u001b[0m 2022-04-12 18:56:08,436\tINFO checkpoint_path.py:15 -- Using RayInternalKVStore for controller checkpoint and recovery.\n", 29 | "\u001b[2m\u001b[36m(ServeController pid=71592)\u001b[0m 2022-04-12 18:56:08,544\tINFO http_state.py:106 -- Starting HTTP proxy with name 'SERVE_CONTROLLER_ACTOR:ziytnj:SERVE_PROXY_ACTOR-node:127.0.0.1-0' on node 'node:127.0.0.1-0' listening on '127.0.0.1:8000'\n", 30 | "2022-04-12 18:56:09,786\tINFO api.py:797 -- Started Serve instance in namespace 'serve'.\n" 31 | ] 32 | }, 33 | { 34 | "data": { 35 | "text/plain": [ 36 | "" 37 | ] 38 | }, 39 | "execution_count": 2, 40 | "metadata": {}, 41 | "output_type": "execute_result" 42 | } 43 | ], 44 | "source": [ 45 | "serve.start()" 46 | ] 47 | }, 48 | { 49 | "cell_type": "markdown", 50 | "id": "55dff614-a30a-44d0-842b-a24e196450a1", 51 | "metadata": {}, 52 | "source": [ 53 | "### Create a Python function deployment " 54 | ] 55 | }, 56 | { 57 | "cell_type": "code", 58 | "execution_count": 3, 59 | "id": "9e8cd218-a831-4e12-b89a-46f878e46b97", 60 | "metadata": {}, 61 | "outputs": [], 62 | "source": [ 63 | "@serve.deployment\n", 64 | "def my_ray_serve_function(request):\n", 65 | " args = request.query_params[\"data\"]\n", 66 | " result = random.random() * float(args)\n", 67 | " return f\"Result: {result:.3f}\" " 68 | ] 69 | }, 70 | { 71 | "cell_type": "code", 72 | "execution_count": 4, 73 | "id": "408bc6bc-70bd-4d15-a9f9-0825253b9933", 74 | "metadata": {}, 75 | "outputs": [ 76 | { 77 | "name": "stderr", 78 | "output_type": "stream", 79 | "text": [ 80 | "2022-04-12 18:56:09,807\tINFO api.py:618 -- Updating deployment 'my_ray_serve_function'. component=serve deployment=my_ray_serve_function\n", 81 | "\u001b[2m\u001b[36m(HTTPProxyActor pid=71609)\u001b[0m INFO: Started server process [71609]\n", 82 | "\u001b[2m\u001b[36m(ServeController pid=71592)\u001b[0m 2022-04-12 18:56:09,816\tINFO deployment_state.py:1210 -- Adding 1 replicas to deployment 'my_ray_serve_function'. component=serve deployment=my_ray_serve_function\n", 83 | "2022-04-12 18:56:11,815\tINFO api.py:633 -- Deployment 'my_ray_serve_function' is ready at `http://127.0.0.1:8000/my_ray_serve_function`. component=serve deployment=my_ray_serve_function\n" 84 | ] 85 | } 86 | ], 87 | "source": [ 88 | "my_ray_serve_function.deploy()" 89 | ] 90 | }, 91 | { 92 | "cell_type": "markdown", 93 | "id": "96d82a0b-0921-456a-8d1c-2a4970f08f1a", 94 | "metadata": {}, 95 | "source": [ 96 | "### Send Request to the function " 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 5, 102 | "id": "5a7f4db8-5819-4a36-a39e-45b620ffb1de", 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "name": "stdout", 107 | "output_type": "stream", 108 | "text": [ 109 | " 0: Result: 0.000\n", 110 | " 1: Result: 0.908\n", 111 | " 2: Result: 0.415\n", 112 | " 3: Result: 1.428\n", 113 | " 4: Result: 0.339\n" 114 | ] 115 | } 116 | ], 117 | "source": [ 118 | "for i in range(5):\n", 119 | " response = requests.get(f\"http://127.0.0.1:8000/my_ray_serve_function?data={i}\").text\n", 120 | " print(f'{i:2d}: {response:}')" 121 | ] 122 | }, 123 | { 124 | "cell_type": "markdown", 125 | "id": "2dde668f-0705-4c9c-88bb-bf468e7c02d1", 126 | "metadata": {}, 127 | "source": [ 128 | "### Create a stateful class" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 17, 134 | "id": "93b5247b-b7c3-4dd0-9919-f460407ce79d", 135 | "metadata": {}, 136 | "outputs": [], 137 | "source": [ 138 | "from random import random\n", 139 | "import starlette\n", 140 | "from starlette.requests import Request\n", 141 | "\n", 142 | "@serve.deployment\n", 143 | "class Model:\n", 144 | " \n", 145 | " def __init__(self, threshold):\n", 146 | " self.threshold = threshold\n", 147 | " \n", 148 | " def __call__(self, starlette_request):\n", 149 | " if isinstance(starlette_request, starlette.requests.Request):\n", 150 | " data = starlette_request.query_params['data']\n", 151 | " else:\n", 152 | " # Request came via a ServerHandle API method call.\n", 153 | " data = starlette_request\n", 154 | " prediction = random() + float(data) if float(data) > self.threshold else float(data)\n", 155 | " return {\"prediction\": prediction}" 156 | ] 157 | }, 158 | { 159 | "cell_type": "code", 160 | "execution_count": 18, 161 | "id": "52e32071-e4d4-4d02-8421-3e542736384c", 162 | "metadata": {}, 163 | "outputs": [ 164 | { 165 | "name": "stderr", 166 | "output_type": "stream", 167 | "text": [ 168 | "2022-04-12 19:02:07,168\tINFO api.py:618 -- Updating deployment 'Model'. component=serve deployment=Model\n", 169 | "\u001b[2m\u001b[36m(ServeController pid=71592)\u001b[0m 2022-04-12 19:02:07,272\tINFO deployment_state.py:1167 -- Stopping 1 replicas of deployment 'Model' with outdated versions. component=serve deployment=Model\n", 170 | "\u001b[2m\u001b[36m(ServeController pid=71592)\u001b[0m 2022-04-12 19:02:09,424\tINFO deployment_state.py:1210 -- Adding 1 replicas to deployment 'Model'. component=serve deployment=Model\n", 171 | "2022-04-12 19:02:11,195\tINFO api.py:633 -- Deployment 'Model' is ready at `http://127.0.0.1:8000/Model`. component=serve deployment=Model\n" 172 | ] 173 | } 174 | ], 175 | "source": [ 176 | "Model.deploy(0.5)" 177 | ] 178 | }, 179 | { 180 | "cell_type": "markdown", 181 | "id": "3e9c9748-eeb2-4937-89e9-5f53f123edd2", 182 | "metadata": {}, 183 | "source": [ 184 | "### Send requests to the model" 185 | ] 186 | }, 187 | { 188 | "cell_type": "code", 189 | "execution_count": 19, 190 | "id": "f5636ab1-823b-4e12-8d6d-bae8a9c03985", 191 | "metadata": {}, 192 | "outputs": [ 193 | { 194 | "name": "stdout", 195 | "output_type": "stream", 196 | "text": [ 197 | "prediction : {\n", 198 | " \"prediction\": 1.5609795907065314\n", 199 | "}\n", 200 | "prediction : {\n", 201 | " \"prediction\": 0.25009238923849064\n", 202 | "}\n", 203 | "prediction : {\n", 204 | " \"prediction\": 0.3763580629780887\n", 205 | "}\n", 206 | "prediction : {\n", 207 | " \"prediction\": 0.30675872742057997\n", 208 | "}\n", 209 | "prediction : {\n", 210 | " \"prediction\": 0.04218724913945959\n", 211 | "}\n" 212 | ] 213 | } 214 | ], 215 | "source": [ 216 | "url = f\"http://127.0.0.1:8000/Model\"\n", 217 | "for i in range(5):\n", 218 | " print(f\"prediction : {requests.get(url, params={'data': random()}).text}\")" 219 | ] 220 | }, 221 | { 222 | "cell_type": "raw", 223 | "id": "54b49569-7f61-4674-987a-19e095151a64", 224 | "metadata": {}, 225 | "source": [ 226 | "serve.shutdown()" 227 | ] 228 | } 229 | ], 230 | "metadata": { 231 | "kernelspec": { 232 | "display_name": "Python 3 (ipykernel)", 233 | "language": "python", 234 | "name": "python3" 235 | }, 236 | "language_info": { 237 | "codemirror_mode": { 238 | "name": "ipython", 239 | "version": 3 240 | }, 241 | "file_extension": ".py", 242 | "mimetype": "text/x-python", 243 | "name": "python", 244 | "nbconvert_exporter": "python", 245 | "pygments_lexer": "ipython3", 246 | "version": "3.8.12" 247 | } 248 | }, 249 | "nbformat": 4, 250 | "nbformat_minor": 5 251 | } 252 | -------------------------------------------------------------------------------- /retired/solutions/ex_10_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": null, 6 | "id": "51bc67b6-1425-441c-b018-ba49b6bd097b", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "sample_request_inputs = [{\n", 11 | " \"sepal length\": 6.3,\n", 12 | " \"sepal width\": 3.3,\n", 13 | " \"petal length\": 6.0,\n", 14 | " \"petal width\": 2.5\n", 15 | " },\n", 16 | " {\n", 17 | " \"sepal length\": 5.1,\n", 18 | " \"sepal width\": 3.5,\n", 19 | " \"petal length\": 1.4,\n", 20 | " \"petal width\": 0.2\n", 21 | " },\n", 22 | " {\n", 23 | " \"sepal length\": 6.4,\n", 24 | " \"sepal width\": 3.2,\n", 25 | " \"petal length\": 4.5,\n", 26 | " \"petal width\": 1.5},\n", 27 | "]" 28 | ] 29 | }, 30 | { 31 | "cell_type": "code", 32 | "execution_count": null, 33 | "id": "8639c07d-c973-43d9-b71a-0ab1ebe0980c", 34 | "metadata": {}, 35 | "outputs": [], 36 | "source": [ 37 | "for input_request in sample_request_inputs:\n", 38 | " response = requests.get(\"http://localhost:8000/regressor\",\n", 39 | " json=input_request)\n", 40 | " print(response.text)" 41 | ] 42 | } 43 | ], 44 | "metadata": { 45 | "kernelspec": { 46 | "display_name": "Python 3 (ipykernel)", 47 | "language": "python", 48 | "name": "python3" 49 | }, 50 | "language_info": { 51 | "codemirror_mode": { 52 | "name": "ipython", 53 | "version": 3 54 | }, 55 | "file_extension": ".py", 56 | "mimetype": "text/x-python", 57 | "name": "python", 58 | "nbconvert_exporter": "python", 59 | "pygments_lexer": "ipython3", 60 | "version": "3.8.12" 61 | } 62 | }, 63 | "nbformat": 4, 64 | "nbformat_minor": 5 65 | } 66 | -------------------------------------------------------------------------------- /retired/submit.py: -------------------------------------------------------------------------------- 1 | import ray 2 | import time 3 | 4 | 5 | @ray.remote(num_cpus=1) 6 | class Actor: 7 | def __init__(self): 8 | self.a = 1 9 | 10 | def f(self): 11 | # time.sleep(1) 12 | self.a += 1 13 | return self.a 14 | 15 | 16 | if __name__ == "__main__": 17 | # connect to the local host with RAY_ADDRESS=127.0.0.1 18 | ray.init(address="auto") 19 | actors = [Actor.remote() for _ in range(5)] 20 | refs = [a.f.remote() for a in actors] 21 | results = ray.get(refs) 22 | print(results) 23 | 24 | 25 | -------------------------------------------------------------------------------- /slides/pydata_nyc/ray-core-tutorial-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/slides/pydata_nyc/ray-core-tutorial-slides.pdf -------------------------------------------------------------------------------- /slides/pydata_seattle/ray-core-tutorial-slides.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/slides/pydata_seattle/ray-core-tutorial-slides.pdf -------------------------------------------------------------------------------- /slides/ucsd/ucsd_lecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dmatrix/ray-core-tutorial/ad5f1fa700d87a9af1e21027f06f02cfdcc937f3/slides/ucsd/ucsd_lecture.pdf -------------------------------------------------------------------------------- /solutions/ex_01_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "db1a7d02-4378-4184-bd08-d29c7ae8d8ab", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import math\n", 11 | "import numpy as np\n", 12 | "import logging\n", 13 | "from typing import List\n", 14 | "import ray" 15 | ] 16 | }, 17 | { 18 | "cell_type": "code", 19 | "execution_count": 2, 20 | "id": "b4ef2d84-4903-429e-96c8-a24210ceec34", 21 | "metadata": {}, 22 | "outputs": [], 23 | "source": [ 24 | "@ray.remote\n", 25 | "def compute_intensive_func(num: int, dims=10) -> List[np.array]:\n", 26 | " dot_products = []\n", 27 | " for _ in range(num):\n", 28 | " # Create a dims x dims matrix\n", 29 | " x = np.random.rand(dims, dims)\n", 30 | " y = np.random.rand(dims, dims)\n", 31 | " \n", 32 | " # Create a dot product of itself\n", 33 | " dot_products.append(np.dot(x, y))\n", 34 | " return dot_products" 35 | ] 36 | }, 37 | { 38 | "cell_type": "code", 39 | "execution_count": 3, 40 | "id": "68e43170-0260-4f7b-91df-4433770145a2", 41 | "metadata": {}, 42 | "outputs": [ 43 | { 44 | "data": { 45 | "text/html": [ 46 | "
\n", 47 | "
\n", 48 | "

Ray

\n", 49 | " \n", 50 | " \n", 51 | " \n", 68 | " \n", 69 | " \n", 70 | " \n", 71 | " \n", 72 | " \n", 73 | " \n", 74 | " \n", 75 | " \n", 76 | " \n", 77 | " \n", 78 | " \n", 79 | " \n", 80 | " \n", 81 | " \n", 82 | "\n", 83 | "\n", 84 | "
Python version:3.8.13
Ray version: 2.3.0
Dashboard:http://127.0.0.1:8265
\n", 85 | "
\n", 86 | "
\n" 87 | ], 88 | "text/plain": [ 89 | "RayContext(dashboard_url='127.0.0.1:8265', python_version='3.8.13', ray_version='2.3.0', ray_commit='cf7a56b4b0b648c324722df7c99c168e92ff0b45', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2023-02-26_10-33-21_402213_21042/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2023-02-26_10-33-21_402213_21042/sockets/raylet', 'webui_url': '127.0.0.1:8265', 'session_dir': '/tmp/ray/session_2023-02-26_10-33-21_402213_21042', 'metrics_export_port': 61990, 'gcs_address': '127.0.0.1:55178', 'address': '127.0.0.1:55178', 'dashboard_agent_listen_port': 52365, 'node_id': 'ad21cbc2ef3080151ad0c70fe15122dfb39fdf8d0018c267ac4641bc'})" 90 | ] 91 | }, 92 | "execution_count": 3, 93 | "metadata": {}, 94 | "output_type": "execute_result" 95 | } 96 | ], 97 | "source": [ 98 | "if ray.is_initialized:\n", 99 | " ray.shutdown()\n", 100 | "ray.init(logging_level=logging.ERROR)" 101 | ] 102 | }, 103 | { 104 | "cell_type": "code", 105 | "execution_count": 4, 106 | "id": "f0677e24-0b30-4831-b348-2ce8147576a8", 107 | "metadata": {}, 108 | "outputs": [ 109 | { 110 | "name": "stdout", 111 | "output_type": "stream", 112 | "text": [ 113 | "CPU times: user 36.6 ms, sys: 11 ms, total: 47.6 ms\n", 114 | "Wall time: 58.1 ms\n" 115 | ] 116 | } 117 | ], 118 | "source": [ 119 | "%%time\n", 120 | "results = [compute_intensive_func.remote(i, 5_000) for i in range(5)]" 121 | ] 122 | }, 123 | { 124 | "cell_type": "code", 125 | "execution_count": 25, 126 | "id": "8482dfac-4043-410c-a75d-1588cfd893c7", 127 | "metadata": {}, 128 | "outputs": [], 129 | "source": [ 130 | "ray.shutdown()" 131 | ] 132 | } 133 | ], 134 | "metadata": { 135 | "kernelspec": { 136 | "display_name": "Python 3 (ipykernel)", 137 | "language": "python", 138 | "name": "python3" 139 | }, 140 | "language_info": { 141 | "codemirror_mode": { 142 | "name": "ipython", 143 | "version": 3 144 | }, 145 | "file_extension": ".py", 146 | "mimetype": "text/x-python", 147 | "name": "python", 148 | "nbconvert_exporter": "python", 149 | "pygments_lexer": "ipython3", 150 | "version": "3.8.13" 151 | } 152 | }, 153 | "nbformat": 4, 154 | "nbformat_minor": 5 155 | } 156 | -------------------------------------------------------------------------------- /solutions/ex_02_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "1be69dae-83d9-43d1-81e7-41c26b683ce3", 7 | "metadata": {}, 8 | "outputs": [ 9 | { 10 | "name": "stdout", 11 | "output_type": "stream", 12 | "text": [ 13 | "RayContext(dashboard_url='127.0.0.1:8267', python_version='3.8.12', ray_version='2.0.0.dev0', ray_commit='{{RAY_COMMIT_SHA}}', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445/sockets/raylet', 'webui_url': '127.0.0.1:8267', 'session_dir': '/tmp/ray/session_2022-04-12_19-26-55_484801_74445', 'metrics_export_port': 65382, 'gcs_address': '127.0.0.1:64612', 'address': '127.0.0.1:64612', 'node_id': '7232289a9b1cd1025eca11df0e1122621f1a665ea41c197b9d9d35c0'})\n" 14 | ] 15 | } 16 | ], 17 | "source": [ 18 | "import logging\n", 19 | "from pprint import pprint\n", 20 | "import ray\n", 21 | "\n", 22 | "if ray.is_initialized:\n", 23 | " ray.shutdown()\n", 24 | "context = ray.init(logging_level=logging.ERROR)\n", 25 | "pprint(context)" 26 | ] 27 | }, 28 | { 29 | "cell_type": "code", 30 | "execution_count": 2, 31 | "id": "0084eab3-f381-430d-a750-74b4a8e434f8", 32 | "metadata": {}, 33 | "outputs": [ 34 | { 35 | "name": "stdout", 36 | "output_type": "stream", 37 | "text": [ 38 | "Dashboard url: http://127.0.0.1:8267\n" 39 | ] 40 | } 41 | ], 42 | "source": [ 43 | "print(f\"Dashboard url: http://{context.address_info['webui_url']}\")" 44 | ] 45 | }, 46 | { 47 | "cell_type": "code", 48 | "execution_count": 6, 49 | "id": "8110da95-01b2-4b73-ba13-f7cfea166329", 50 | "metadata": {}, 51 | "outputs": [], 52 | "source": [ 53 | "@ray.remote\n", 54 | "def my_function (num_list):\n", 55 | " return sum(num_list)" 56 | ] 57 | }, 58 | { 59 | "cell_type": "markdown", 60 | "id": "7bf709bd-217c-4553-80c1-042c7dddb34f", 61 | "metadata": {}, 62 | "source": [ 63 | "### Method 1\n", 64 | "\n", 65 | "Without comprehension" 66 | ] 67 | }, 68 | { 69 | "cell_type": "code", 70 | "execution_count": 11, 71 | "id": "7618f6df-f2b6-4286-9dae-fe24497caae0", 72 | "metadata": {}, 73 | "outputs": [ 74 | { 75 | "data": { 76 | "text/plain": [ 77 | "[ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000015000000),\n", 78 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000016000000),\n", 79 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000017000000),\n", 80 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000018000000),\n", 81 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff0100000019000000),\n", 82 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001a000000),\n", 83 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001b000000),\n", 84 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001c000000),\n", 85 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001d000000),\n", 86 | " ObjectRef(00ffffffffffffffffffffffffffffffffffffff010000001e000000)]" 87 | ] 88 | }, 89 | "execution_count": 11, 90 | "metadata": {}, 91 | "output_type": "execute_result" 92 | } 93 | ], 94 | "source": [ 95 | "obj_refs = [ray.put(i) for i in range(10)]\n", 96 | "obj_refs" 97 | ] 98 | }, 99 | { 100 | "cell_type": "code", 101 | "execution_count": 13, 102 | "id": "6835d594-e51d-4da8-a53c-01d7d6c39e44", 103 | "metadata": {}, 104 | "outputs": [ 105 | { 106 | "data": { 107 | "text/plain": [ 108 | "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]" 109 | ] 110 | }, 111 | "execution_count": 13, 112 | "metadata": {}, 113 | "output_type": "execute_result" 114 | } 115 | ], 116 | "source": [ 117 | "values = ray.get(obj_refs)\n", 118 | "values" 119 | ] 120 | }, 121 | { 122 | "cell_type": "code", 123 | "execution_count": 14, 124 | "id": "4a48c181-a6c8-41fe-bf71-78ceaaff2fef", 125 | "metadata": {}, 126 | "outputs": [], 127 | "source": [ 128 | "sum_obj_ref = my_function.remote(values)" 129 | ] 130 | }, 131 | { 132 | "cell_type": "code", 133 | "execution_count": 15, 134 | "id": "3ec83055-db03-4651-959b-26d116905ea5", 135 | "metadata": {}, 136 | "outputs": [ 137 | { 138 | "data": { 139 | "text/plain": [ 140 | "45" 141 | ] 142 | }, 143 | "execution_count": 15, 144 | "metadata": {}, 145 | "output_type": "execute_result" 146 | } 147 | ], 148 | "source": [ 149 | "ray.get(sum_obj_ref)" 150 | ] 151 | }, 152 | { 153 | "cell_type": "markdown", 154 | "id": "85096fa6-8cea-4b50-aff7-3b4857df64ec", 155 | "metadata": {}, 156 | "source": [ 157 | "### Method 2\n", 158 | "Using comprehension" 159 | ] 160 | }, 161 | { 162 | "cell_type": "code", 163 | "execution_count": 16, 164 | "id": "33f2a5d0-ea98-4997-9cde-c3cf7d801f85", 165 | "metadata": {}, 166 | "outputs": [ 167 | { 168 | "data": { 169 | "text/plain": [ 170 | "45" 171 | ] 172 | }, 173 | "execution_count": 16, 174 | "metadata": {}, 175 | "output_type": "execute_result" 176 | } 177 | ], 178 | "source": [ 179 | "ray.get(my_function.remote(ray.get([ray.put(i) for i in range(10)])))" 180 | ] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 3 (ipykernel)", 186 | "language": "python", 187 | "name": "python3" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 3 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython3", 199 | "version": "3.8.13" 200 | } 201 | }, 202 | "nbformat": 4, 203 | "nbformat_minor": 5 204 | } 205 | -------------------------------------------------------------------------------- /solutions/ex_03_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 6, 6 | "id": "b456a148-3f34-468f-a889-3f319489444b", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import logging\n", 11 | "import time\n", 12 | "import os\n", 13 | "import math\n", 14 | "import ray\n", 15 | "import random\n", 16 | "import tqdm\n", 17 | "from typing import Dict, Tuple, List\n", 18 | "from random import randint\n", 19 | "import numpy as np" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": 7, 25 | "id": "834f3f49-5ce3-4942-a8d2-7aa490fdb73b", 26 | "metadata": {}, 27 | "outputs": [ 28 | { 29 | "data": { 30 | "text/html": [ 31 | "
\n", 32 | "
\n", 33 | "

Ray

\n", 34 | " \n", 35 | " \n", 36 | " \n", 53 | " \n", 54 | " \n", 55 | " \n", 56 | " \n", 57 | " \n", 58 | " \n", 59 | " \n", 60 | " \n", 61 | " \n", 62 | " \n", 63 | " \n", 64 | " \n", 65 | " \n", 66 | " \n", 67 | "\n", 68 | "\n", 69 | "
Python version:3.8.13
Ray version: 2.3.0
Dashboard:http://127.0.0.1:8267
\n", 70 | "
\n", 71 | "
\n" 72 | ], 73 | "text/plain": [ 74 | "RayContext(dashboard_url='127.0.0.1:8267', python_version='3.8.13', ray_version='2.3.0', ray_commit='cf7a56b4b0b648c324722df7c99c168e92ff0b45', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2023-02-26_14-26-54_960980_73058/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2023-02-26_14-26-54_960980_73058/sockets/raylet', 'webui_url': '127.0.0.1:8267', 'session_dir': '/tmp/ray/session_2023-02-26_14-26-54_960980_73058', 'metrics_export_port': 59961, 'gcs_address': '127.0.0.1:57533', 'address': '127.0.0.1:57533', 'dashboard_agent_listen_port': 52365, 'node_id': 'c707f34390057228d0d268e603e8536ce4d45fa04b7cc2a6f45e9548'})" 75 | ] 76 | }, 77 | "execution_count": 7, 78 | "metadata": {}, 79 | "output_type": "execute_result" 80 | } 81 | ], 82 | "source": [ 83 | "if ray.is_initialized:\n", 84 | " ray.shutdown()\n", 85 | "ray.init(logging_level=logging.ERROR)" 86 | ] 87 | }, 88 | { 89 | "cell_type": "code", 90 | "execution_count": 8, 91 | "id": "1098ee33-9bec-4345-ba87-4a1ed9b87437", 92 | "metadata": {}, 93 | "outputs": [], 94 | "source": [ 95 | "class ActorCls:\n", 96 | " def __init__(self, name: str):\n", 97 | " self.name = name\n", 98 | " self.method_calls = {\"method\": 0}\n", 99 | "\n", 100 | " def method(self, **args) -> None:\n", 101 | " # Overwrite this method in the subclass\n", 102 | " pass\n", 103 | "\n", 104 | " def get_all_method_calls(self) -> Tuple[str, Dict[str, int]]:\n", 105 | " return self.get_name(), self.method_calls\n", 106 | " \n", 107 | " def get_name(self) -> str:\n", 108 | " return self.name" 109 | ] 110 | }, 111 | { 112 | "cell_type": "code", 113 | "execution_count": 9, 114 | "id": "5ce35e3d-566e-493a-99c1-560eb1ca0788", 115 | "metadata": {}, 116 | "outputs": [], 117 | "source": [ 118 | "@ray.remote\n", 119 | "class ActorClsOne(ActorCls):\n", 120 | " \n", 121 | " def __init__(self, name: str):\n", 122 | " super().__init__(name)\n", 123 | " \n", 124 | " def method(self, **args) -> None:\n", 125 | " # do something with kwargs here\n", 126 | " time.sleep(args[\"timeout\"])\n", 127 | " \n", 128 | " # update the respective counter\n", 129 | " self.method_calls[\"method\"] += 1" 130 | ] 131 | }, 132 | { 133 | "cell_type": "code", 134 | "execution_count": 10, 135 | "id": "93940068-fde2-48da-9621-c7bb769cf300", 136 | "metadata": {}, 137 | "outputs": [], 138 | "source": [ 139 | "@ray.remote\n", 140 | "class ActorClsTwo(ActorCls):\n", 141 | " \n", 142 | " def __init__(self, name: str):\n", 143 | " super().__init__(name)\n", 144 | " \n", 145 | " def method(self, **args) -> None:\n", 146 | " # do something with kwargs here\n", 147 | " time.sleep(args[\"timeout\"])\n", 148 | " \n", 149 | " # update the respective counter\n", 150 | " self.method_calls[\"method\"] += 1" 151 | ] 152 | }, 153 | { 154 | "cell_type": "code", 155 | "execution_count": 11, 156 | "id": "42b7346a-e3e0-4074-a426-8753b1df687e", 157 | "metadata": {}, 158 | "outputs": [], 159 | "source": [ 160 | "@ray.remote\n", 161 | "class ActorClsThree(ActorCls):\n", 162 | " \n", 163 | " def __init__(self, name: str):\n", 164 | " super().__init__(name)\n", 165 | " \n", 166 | " def method(self, **args) -> None:\n", 167 | " # do something with kwargs here\n", 168 | " time.sleep(args[\"timeout\"])\n", 169 | " \n", 170 | " # update the respective counter\n", 171 | " self.method_calls[\"method\"] += 1" 172 | ] 173 | }, 174 | { 175 | "cell_type": "code", 176 | "execution_count": 12, 177 | "id": "8aa5fc45-b15b-4c2d-aec1-9c051d37c423", 178 | "metadata": {}, 179 | "outputs": [], 180 | "source": [ 181 | "actor_one = ActorClsOne.remote(\"ActorClsOne\")\n", 182 | "actor_two = ActorClsTwo.remote(\"ActorClsTwo\")\n", 183 | "actor_three = ActorClsTwo.remote(\"ActorClsThree\")" 184 | ] 185 | }, 186 | { 187 | "cell_type": "code", 188 | "execution_count": 14, 189 | "id": "c30cb397-2f64-491c-9a34-60f3687e9b5d", 190 | "metadata": {}, 191 | "outputs": [], 192 | "source": [ 193 | "# A list of Actor classes\n", 194 | "CALLERS_NAMES = [\"ActorClsOne\", \"ActorClsTwo\", \"ActorClsThree\"]\n", 195 | "\n", 196 | "# A dictionary of Actor instances\n", 197 | "CALLERS_CLS_DICT = {\"ActorClsOne\": actor_one, \n", 198 | " \"ActorClsTwo\": actor_two,\n", 199 | " \"ActorClsThree\": actor_three}" 200 | ] 201 | }, 202 | { 203 | "cell_type": "code", 204 | "execution_count": 15, 205 | "id": "22a4f44a-77b2-4459-a863-84b986eb5a1b", 206 | "metadata": {}, 207 | "outputs": [ 208 | { 209 | "name": "stdout", 210 | "output_type": "stream", 211 | "text": [ 212 | "State of counts in this execution: {'ActorClsOne': 3, 'ActorClsTwo': 8, 'ActorClsThree': 4}\n", 213 | "State of counts in this execution: {'ActorClsOne': 6, 'ActorClsTwo': 14, 'ActorClsThree': 10}\n", 214 | "State of counts in this execution: {'ActorClsOne': 10, 'ActorClsTwo': 17, 'ActorClsThree': 18}\n" 215 | ] 216 | } 217 | ], 218 | "source": [ 219 | "count_dict = {\"ActorClsOne\": 0, \"ActorClsTwo\": 0, \"ActorClsThree\": 0}\n", 220 | "for _ in range(len(CALLERS_NAMES)): \n", 221 | " for _ in range(15):\n", 222 | " name = random.choice(CALLERS_NAMES)\n", 223 | " count_dict[name] += 1 \n", 224 | " CALLERS_CLS_DICT[name].method.remote(timeout=1, store=\"mongo_db\") if name == \"ActorClsOne\" else CALLERS_CLS_DICT[name].method.remote(timeout=1.5, store=\"delta\")\n", 225 | " \n", 226 | " print(f\"State of counts in this execution: {count_dict}\")\n", 227 | " time.sleep(0.5)" 228 | ] 229 | }, 230 | { 231 | "cell_type": "code", 232 | "execution_count": 16, 233 | "id": "a2897704-2400-4731-b6e9-44164aa46db8", 234 | "metadata": {}, 235 | "outputs": [ 236 | { 237 | "name": "stdout", 238 | "output_type": "stream", 239 | "text": [ 240 | "[('ActorClsOne', {'method': 10}), ('ActorClsTwo', {'method': 17}), ('ActorClsThree', {'method': 18})]\n" 241 | ] 242 | } 243 | ], 244 | "source": [ 245 | "print(ray.get([CALLERS_CLS_DICT[name].get_all_method_calls.remote() for name in CALLERS_NAMES]))" 246 | ] 247 | }, 248 | { 249 | "cell_type": "code", 250 | "execution_count": 17, 251 | "id": "8a2d525b-da65-41b2-bf32-f950926bbd31", 252 | "metadata": {}, 253 | "outputs": [], 254 | "source": [ 255 | "ray.shutdown()" 256 | ] 257 | } 258 | ], 259 | "metadata": { 260 | "kernelspec": { 261 | "display_name": "Python 3 (ipykernel)", 262 | "language": "python", 263 | "name": "python3" 264 | }, 265 | "language_info": { 266 | "codemirror_mode": { 267 | "name": "ipython", 268 | "version": 3 269 | }, 270 | "file_extension": ".py", 271 | "mimetype": "text/x-python", 272 | "name": "python", 273 | "nbconvert_exporter": "python", 274 | "pygments_lexer": "ipython3", 275 | "version": "3.8.13" 276 | } 277 | }, 278 | "nbformat": 4, 279 | "nbformat_minor": 5 280 | } 281 | -------------------------------------------------------------------------------- /solutions/ex_04_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "e425ccaf-273b-4126-8b2b-147dbbd8aa8a", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "import logging\n", 11 | "import time\n", 12 | "import ray\n", 13 | "import random\n", 14 | "from random import randint\n", 15 | "import numpy as np" 16 | ] 17 | }, 18 | { 19 | "cell_type": "code", 20 | "execution_count": 2, 21 | "id": "2f61c376-5c2f-4f26-bd57-1b50624dadbd", 22 | "metadata": {}, 23 | "outputs": [], 24 | "source": [ 25 | "from collections import defaultdict\n", 26 | "@ray.remote\n", 27 | "class LoggingActor(object):\n", 28 | " def __init__(self):\n", 29 | " # create a container of dictionaries.\n", 30 | " self.logs = defaultdict(list)\n", 31 | " \n", 32 | " # log the message for a particular experiment in its \n", 33 | " # respective dictionary\n", 34 | " def log(self, index, message):\n", 35 | " self.logs[index].append(message)\n", 36 | " \n", 37 | " # fetch all logs as collection\n", 38 | " def get_logs(self):\n", 39 | " return dict(self.logs)\n", 40 | " \n", 41 | "@ray.remote\n", 42 | "def run_experiment(experiment_index, logging_actor):\n", 43 | " for i in range(9):\n", 44 | " # pretend this is an experiment that produces a nine results for \n", 45 | " # experiment result; in our case it's just a simple message \n", 46 | " # Push a logging message to the actor.\n", 47 | " exp_key = f\"experiment-{experiment_index}\"\n", 48 | " logging_actor.log.remote(exp_key, 'On iteration {}'.format(i)) " 49 | ] 50 | }, 51 | { 52 | "cell_type": "code", 53 | "execution_count": 3, 54 | "id": "566abe08-0af6-42e7-ba57-532166f4d0ce", 55 | "metadata": {}, 56 | "outputs": [ 57 | { 58 | "data": { 59 | "text/html": [ 60 | "
\n", 61 | "
\n", 62 | "

Ray

\n", 63 | " \n", 64 | " \n", 65 | " \n", 82 | " \n", 83 | " \n", 84 | " \n", 85 | " \n", 86 | " \n", 87 | " \n", 88 | " \n", 89 | " \n", 90 | " \n", 91 | " \n", 92 | " \n", 93 | " \n", 94 | " \n", 95 | " \n", 96 | "\n", 97 | "\n", 98 | "
Python version:3.8.13
Ray version: 2.0.1
Dashboard:http://127.0.0.1:8265
\n", 99 | "
\n", 100 | "
\n" 101 | ], 102 | "text/plain": [ 103 | "RayContext(dashboard_url='127.0.0.1:8265', python_version='3.8.13', ray_version='2.0.1', ray_commit='03b6bc7b5a305877501110ec04710a9c57011479', address_info={'node_ip_address': '127.0.0.1', 'raylet_ip_address': '127.0.0.1', 'redis_address': None, 'object_store_address': '/tmp/ray/session_2022-11-10_04-04-44_290983_62756/sockets/plasma_store', 'raylet_socket_name': '/tmp/ray/session_2022-11-10_04-04-44_290983_62756/sockets/raylet', 'webui_url': '127.0.0.1:8265', 'session_dir': '/tmp/ray/session_2022-11-10_04-04-44_290983_62756', 'metrics_export_port': 55660, 'gcs_address': '127.0.0.1:52014', 'address': '127.0.0.1:52014', 'dashboard_agent_listen_port': 52365, 'node_id': '155073a0c7205bde87bbee5cc38570f21f97730a7032ebdac36ba251'})" 104 | ] 105 | }, 106 | "execution_count": 3, 107 | "metadata": {}, 108 | "output_type": "execute_result" 109 | } 110 | ], 111 | "source": [ 112 | "if ray.is_initialized:\n", 113 | " ray.shutdown()\n", 114 | "ray.init(logging_level=logging.ERROR)" 115 | ] 116 | }, 117 | { 118 | "cell_type": "markdown", 119 | "id": "272895a1-4fb1-4235-9ddd-65e76930554e", 120 | "metadata": {}, 121 | "source": [ 122 | "Run three experiments." 123 | ] 124 | }, 125 | { 126 | "cell_type": "code", 127 | "execution_count": 4, 128 | "id": "cd2a3f51-92a1-4ff9-8d22-56b47ebf69da", 129 | "metadata": {}, 130 | "outputs": [], 131 | "source": [ 132 | "logging_actor = LoggingActor.remote()\n", 133 | "experiment_ids = []\n", 134 | "# Run three different experiments\n", 135 | "for i in range(3):\n", 136 | " experiment_ids.append(run_experiment.remote(i, logging_actor))" 137 | ] 138 | }, 139 | { 140 | "cell_type": "markdown", 141 | "id": "50212dd0-bd49-48f0-b5b2-27cb0baa3d52", 142 | "metadata": {}, 143 | "source": [ 144 | "### Fetch the results \n", 145 | "\n", 146 | "For each experement, we will have 9 iteration results" 147 | ] 148 | }, 149 | { 150 | "cell_type": "code", 151 | "execution_count": 5, 152 | "id": "3ed4fc03-339f-4866-a3ef-dfd12051d078", 153 | "metadata": {}, 154 | "outputs": [ 155 | { 156 | "name": "stdout", 157 | "output_type": "stream", 158 | "text": [ 159 | "{'experiment-0': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-1': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-2': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8']}\n", 160 | "{'experiment-0': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-1': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-2': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8']}\n", 161 | "{'experiment-0': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-1': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8'], 'experiment-2': ['On iteration 0', 'On iteration 1', 'On iteration 2', 'On iteration 3', 'On iteration 4', 'On iteration 5', 'On iteration 6', 'On iteration 7', 'On iteration 8']}\n" 162 | ] 163 | } 164 | ], 165 | "source": [ 166 | "for i in range(3):\n", 167 | " time.sleep(1)\n", 168 | " logs = logging_actor.get_logs.remote()\n", 169 | " print(ray.get(logs))" 170 | ] 171 | }, 172 | { 173 | "cell_type": "code", 174 | "execution_count": 6, 175 | "id": "13c39791-63e1-4563-9d7c-e9aab7700d34", 176 | "metadata": {}, 177 | "outputs": [], 178 | "source": [ 179 | "ray.shutdown()" 180 | ] 181 | } 182 | ], 183 | "metadata": { 184 | "kernelspec": { 185 | "display_name": "Python 3 (ipykernel)", 186 | "language": "python", 187 | "name": "python3" 188 | }, 189 | "language_info": { 190 | "codemirror_mode": { 191 | "name": "ipython", 192 | "version": 3 193 | }, 194 | "file_extension": ".py", 195 | "mimetype": "text/x-python", 196 | "name": "python", 197 | "nbconvert_exporter": "python", 198 | "pygments_lexer": "ipython3", 199 | "version": "3.8.13" 200 | } 201 | }, 202 | "nbformat": 4, 203 | "nbformat_minor": 5 204 | } 205 | -------------------------------------------------------------------------------- /solutions/ex_05_solution.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "code", 5 | "execution_count": 1, 6 | "id": "de7fdaf6-ab3a-4bb1-9c86-880e7b70ca01", 7 | "metadata": {}, 8 | "outputs": [], 9 | "source": [ 10 | "def task(n):\n", 11 | " # Simulate a long intensive task\n", 12 | " time.sleep(0.5 * n)\n", 13 | " \n", 14 | " # do some matrix computation and return results\n", 15 | " array_1 = np.random.randint(n*50, size=n) * 0.05\n", 16 | " array_2 = np.random.randint(n * 50, size=n) * 0.03\n", 17 | " \n", 18 | " return np.sum(array_1) + np.sum(array_2)" 19 | ] 20 | } 21 | ], 22 | "metadata": { 23 | "kernelspec": { 24 | "display_name": "Python 3 (ipykernel)", 25 | "language": "python", 26 | "name": "python3" 27 | }, 28 | "language_info": { 29 | "codemirror_mode": { 30 | "name": "ipython", 31 | "version": 3 32 | }, 33 | "file_extension": ".py", 34 | "mimetype": "text/x-python", 35 | "name": "python", 36 | "nbconvert_exporter": "python", 37 | "pygments_lexer": "ipython3", 38 | "version": "3.8.13" 39 | } 40 | }, 41 | "nbformat": 4, 42 | "nbformat_minor": 5 43 | } 44 | -------------------------------------------------------------------------------- /solutions/ex_07_solutions.ipynb: -------------------------------------------------------------------------------- 1 | { 2 | "cells": [ 3 | { 4 | "cell_type": "markdown", 5 | "id": "86278823-aee6-4cab-b9bd-ccde1a926182", 6 | "metadata": {}, 7 | "source": [ 8 | "### Adding a new column" 9 | ] 10 | }, 11 | { 12 | "cell_type": "code", 13 | "execution_count": null, 14 | "id": "8ae90694-0926-44a8-8b70-2d4b8e986aa2", 15 | "metadata": {}, 16 | "outputs": [], 17 | "source": [ 18 | "new_ds = arrow_ds.add_colum(\"age\", lambda df: random.randint(21,65))\n", 19 | "new_ds.schema()" 20 | ] 21 | }, 22 | { 23 | "cell_type": "code", 24 | "execution_count": null, 25 | "id": "44a8009f-f6b7-47c8-be47-1036cc086215", 26 | "metadata": {}, 27 | "outputs": [], 28 | "source": [ 29 | "new_ds.take(1)" 30 | ] 31 | }, 32 | { 33 | "cell_type": "markdown", 34 | "id": "5f5e9b47-77f2-4518-a741-9cf344cd557b", 35 | "metadata": {}, 36 | "source": [ 37 | "### Filter by gender (U)" 38 | ] 39 | }, 40 | { 41 | "cell_type": "code", 42 | "execution_count": null, 43 | "id": "a35fd359-480d-4695-9807-45087dd96803", 44 | "metadata": {}, 45 | "outputs": [], 46 | "source": [ 47 | "arrow_ds.map_batches(lambda df: df[df[\"gender\"] == \"U\"]).take(3)" 48 | ] 49 | }, 50 | { 51 | "cell_type": "markdown", 52 | "id": "72e8ca22-348b-4bbf-8971-819d7e3fcd55", 53 | "metadata": {}, 54 | "source": [ 55 | "### Groupby property" 56 | ] 57 | }, 58 | { 59 | "cell_type": "code", 60 | "execution_count": null, 61 | "id": "fab8ff59-7560-4751-9ebe-4bff3ee4cf3e", 62 | "metadata": {}, 63 | "outputs": [], 64 | "source": [ 65 | "results = arrow_ds.groupby(\"property\").count()\n", 66 | "results.show()" 67 | ] 68 | }, 69 | { 70 | "cell_type": "markdown", 71 | "id": "13851d83-bfec-4b01-8da6-2450229e78de", 72 | "metadata": {}, 73 | "source": [ 74 | "### Modify pipeline function" 75 | ] 76 | }, 77 | { 78 | "cell_type": "code", 79 | "execution_count": null, 80 | "id": "1cfcff5f-ddb5-493c-bf25-bf478f167bd5", 81 | "metadata": {}, 82 | "outputs": [], 83 | "source": [ 84 | "def count_tx(row: ray.data.impl.arrow_block.ArrowRow) -> int:\n", 85 | " return 1 if row['state'] == \"TX\" and row[\"defaulted\"] and row['marital_status' == 'married'] and else 0" 86 | ] 87 | } 88 | ], 89 | "metadata": { 90 | "kernelspec": { 91 | "display_name": "Python 3 (ipykernel)", 92 | "language": "python", 93 | "name": "python3" 94 | }, 95 | "language_info": { 96 | "codemirror_mode": { 97 | "name": "ipython", 98 | "version": 3 99 | }, 100 | "file_extension": ".py", 101 | "mimetype": "text/x-python", 102 | "name": "python", 103 | "nbconvert_exporter": "python", 104 | "pygments_lexer": "ipython3", 105 | "version": "3.8.13" 106 | } 107 | }, 108 | "nbformat": 4, 109 | "nbformat_minor": 5 110 | } 111 | -------------------------------------------------------------------------------- /tasks_helper_utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | import requests 3 | import random 4 | import time 5 | import tqdm 6 | from pathlib import Path 7 | from PIL import Image, ImageFilter 8 | from typing import List, Tuple 9 | import torch 10 | import numpy as np 11 | import pandas as pd 12 | import matplotlib.pyplot as plt 13 | from torchvision import transforms as T 14 | import ray 15 | 16 | 17 | # 18 | # borrowed URLs ideas and heavily modified from https://analyticsindiamag.com/how-to-run-python-code-concurrently-using-multithreading/ 19 | # 20 | 21 | URLS = [ 22 | 'https://images.pexels.com/photos/305821/pexels-photo-305821.jpeg', 23 | 'https://images.pexels.com/photos/509922/pexels-photo-509922.jpeg', 24 | 'https://images.pexels.com/photos/325812/pexels-photo-325812.jpeg', 25 | 'https://images.pexels.com/photos/1252814/pexels-photo-1252814.jpeg', 26 | 'https://images.pexels.com/photos/1420709/pexels-photo-1420709.jpeg', 27 | 'https://images.pexels.com/photos/963486/pexels-photo-963486.jpeg', 28 | 'https://images.pexels.com/photos/1557183/pexels-photo-1557183.jpeg', 29 | 'https://images.pexels.com/photos/3023211/pexels-photo-3023211.jpeg', 30 | 'https://images.pexels.com/photos/1031641/pexels-photo-1031641.jpeg', 31 | 'https://images.pexels.com/photos/439227/pexels-photo-439227.jpeg', 32 | 'https://images.pexels.com/photos/696644/pexels-photo-696644.jpeg', 33 | 'https://images.pexels.com/photos/911254/pexels-photo-911254.jpeg', 34 | 'https://images.pexels.com/photos/1001990/pexels-photo-1001990.jpeg', 35 | 'https://images.pexels.com/photos/3518623/pexels-photo-3518623.jpeg', 36 | 'https://images.pexels.com/photos/916044/pexels-photo-916044.jpeg', 37 | 'https://images.pexels.com/photos/2253879/pexels-photo-2253879.jpeg', 38 | 'https://images.pexels.com/photos/3316918/pexels-photo-3316918.jpeg', 39 | 'https://images.pexels.com/photos/942317/pexels-photo-942317.jpeg', 40 | 'https://images.pexels.com/photos/1090638/pexels-photo-1090638.jpeg', 41 | 'https://images.pexels.com/photos/1279813/pexels-photo-1279813.jpeg', 42 | 'https://images.pexels.com/photos/434645/pexels-photo-434645.jpeg', 43 | 'https://images.pexels.com/photos/1571460/pexels-photo-1571460.jpeg', 44 | 'https://images.pexels.com/photos/1080696/pexels-photo-1080696.jpeg', 45 | 'https://images.pexels.com/photos/271816/pexels-photo-271816.jpeg', 46 | 'https://images.pexels.com/photos/421927/pexels-photo-421927.jpeg', 47 | 'https://images.pexels.com/photos/302428/pexels-photo-302428.jpeg', 48 | 'https://images.pexels.com/photos/443383/pexels-photo-443383.jpeg', 49 | 'https://images.pexels.com/photos/3685175/pexels-photo-3685175.jpeg', 50 | 'https://images.pexels.com/photos/2885578/pexels-photo-2885578.jpeg', 51 | 'https://images.pexels.com/photos/3530116/pexels-photo-3530116.jpeg', 52 | 'https://images.pexels.com/photos/9668911/pexels-photo-9668911.jpeg', 53 | 'https://images.pexels.com/photos/14704971/pexels-photo-14704971.jpeg', 54 | 'https://images.pexels.com/photos/13865510/pexels-photo-13865510.jpeg', 55 | 'https://images.pexels.com/photos/6607387/pexels-photo-6607387.jpeg', 56 | 'https://images.pexels.com/photos/13716813/pexels-photo-13716813.jpeg', 57 | 'https://images.pexels.com/photos/14690500/pexels-photo-14690500.jpeg', 58 | 'https://images.pexels.com/photos/14690501/pexels-photo-14690501.jpeg', 59 | 'https://images.pexels.com/photos/14615366/pexels-photo-14615366.jpeg', 60 | 'https://images.pexels.com/photos/14344696/pexels-photo-14344696.jpeg', 61 | 'https://images.pexels.com/photos/14661919/pexels-photo-14661919.jpeg', 62 | 'https://images.pexels.com/photos/5977791/pexels-photo-5977791.jpeg', 63 | 'https://images.pexels.com/photos/5211747/pexels-photo-5211747.jpeg', 64 | 'https://images.pexels.com/photos/5995657/pexels-photo-5995657.jpeg', 65 | 'https://images.pexels.com/photos/8574183/pexels-photo-8574183.jpeg', 66 | 'https://images.pexels.com/photos/14690503/pexels-photo-14690503.jpeg', 67 | 'https://images.pexels.com/photos/2100941/pexels-photo-2100941.jpeg', 68 | 'https://images.pexels.com/photos/210019/pexels-photo-210019.jpeg', 69 | 'https://images.pexels.com/photos/112460/pexels-photo-112460.jpeg', 70 | 'https://images.pexels.com/photos/116675/pexels-photo-116675.jpeg', 71 | 'https://images.pexels.com/photos/3586966/pexels-photo-3586966.jpeg', 72 | 'https://images.pexels.com/photos/313782/pexels-photo-313782.jpeg', 73 | 'https://www.nasa.gov/centers/stennis/images/content/702979main_SSC-2012-01487.jpg', 74 | 'https://live.staticflickr.com/2443/3984080835_71b0426844_b.jpg', 75 | 'https://www.aero.jaxa.jp/eng/facilities/aeroengine/images/th_aeroengine05.jpg', 76 | 'https://images.pexels.com/photos/370717/pexels-photo-370717.jpeg', 77 | 'https://images.pexels.com/photos/1323550/pexels-photo-1323550.jpeg', 78 | 'https://images.pexels.com/photos/11374974/pexels-photo-11374974.jpeg', 79 | 'https://images.pexels.com/photos/408951/pexels-photo-408951.jpeg', 80 | 'https://images.pexels.com/photos/3889870/pexels-photo-3889870.jpeg', 81 | 'https://images.pexels.com/photos/1774389/pexels-photo-1774389.jpeg', 82 | 'https://images.pexels.com/photos/3889854/pexels-photo-3889854.jpeg', 83 | 'https://images.pexels.com/photos/2196578/pexels-photo-2196578.jpeg', 84 | 'https://images.pexels.com/photos/2885320/pexels-photo-2885320.jpeg', 85 | 'https://images.pexels.com/photos/7189303/pexels-photo-7189303.jpeg', 86 | 'https://images.pexels.com/photos/9697598/pexels-photo-9697598.jpeg', 87 | 'https://images.pexels.com/photos/6431298/pexels-photo-6431298.jpeg', 88 | 'https://images.pexels.com/photos/7131157/pexels-photo-7131157.jpeg', 89 | 'https://images.pexels.com/photos/4840134/pexels-photo-4840134.jpeg', 90 | 'https://images.pexels.com/photos/5359974/pexels-photo-5359974.jpeg', 91 | 'https://images.pexels.com/photos/3889854/pexels-photo-3889854.jpeg', 92 | 'https://images.pexels.com/photos/1753272/pexels-photo-1753272.jpeg', 93 | 'https://images.pexels.com/photos/2328863/pexels-photo-2328863.jpeg', 94 | 'https://images.pexels.com/photos/6102161/pexels-photo-6102161.jpeg', 95 | 'https://images.pexels.com/photos/6101986/pexels-photo-6101986.jpeg', 96 | 'https://images.pexels.com/photos/3334492/pexels-photo-3334492.jpeg', 97 | 'https://images.pexels.com/photos/5708915/pexels-photo-5708915.jpeg', 98 | 'https://images.pexels.com/photos/5708913/pexels-photo-5708913.jpeg', 99 | 'https://images.pexels.com/photos/6102436/pexels-photo-6102436.jpeg', 100 | 'https://images.pexels.com/photos/6102144/pexels-photo-6102144.jpeg', 101 | 'https://images.pexels.com/photos/6102003/pexels-photo-6102003.jpeg', 102 | 'https://images.pexels.com/photos/6194087/pexels-photo-6194087.jpeg', 103 | 'https://images.pexels.com/photos/5847900/pexels-photo-5847900.jpeg', 104 | 'https://images.pexels.com/photos/1671479/pexels-photo-1671479.jpeg', 105 | 'https://images.pexels.com/photos/3335507/pexels-photo-3335507.jpeg', 106 | 'https://images.pexels.com/photos/6102522/pexels-photo-6102522.jpeg', 107 | 'https://images.pexels.com/photos/6211095/pexels-photo-6211095.jpeg', 108 | 'https://images.pexels.com/photos/720347/pexels-photo-720347.jpeg', 109 | 'https://images.pexels.com/photos/3516015/pexels-photo-3516015.jpeg', 110 | 'https://images.pexels.com/photos/3325717/pexels-photo-3325717.jpeg', 111 | 'https://images.pexels.com/photos/849835/pexels-photo-849835.jpeg', 112 | 'https://images.pexels.com/photos/302743/pexels-photo-302743.jpeg', 113 | 'https://images.pexels.com/photos/167699/pexels-photo-167699.jpeg', 114 | 'https://images.pexels.com/photos/259620/pexels-photo-259620.jpeg', 115 | 'https://images.pexels.com/photos/300857/pexels-photo-300857.jpeg', 116 | 'https://images.pexels.com/photos/789380/pexels-photo-789380.jpeg', 117 | 'https://images.pexels.com/photos/735987/pexels-photo-735987.jpeg', 118 | 'https://images.pexels.com/photos/572897/pexels-photo-572897.jpeg', 119 | 'https://images.pexels.com/photos/300857/pexels-photo-300857.jpeg', 120 | 'https://images.pexels.com/photos/760971/pexels-photo-760971.jpeg', 121 | 'https://images.pexels.com/photos/789382/pexels-photo-789382.jpeg', 122 | 'https://images.pexels.com/photos/33041/antelope-canyon-lower-canyon-arizona.jpg', 123 | 'https://images.pexels.com/photos/1004665/pexels-photo-1004665.jpeg' 124 | ] 125 | THUMB_SIZE = (64, 64) 126 | 127 | def extract_times(lst: Tuple[int, float]) -> List[float]: 128 | """ 129 | Given a list of Tuples[batch_size, execution_time] extract the latter 130 | """ 131 | times = [t[1] for t in lst] 132 | return times 133 | 134 | def plot_times(batches: List[int], s_lst: List[float], d_lst: List[float]) -> None: 135 | """ 136 | Plot the execution times for serail vs distributed for each respective batch size of images 137 | """ 138 | s_times = extract_times(s_lst) 139 | d_times = extract_times(d_lst) 140 | data = {'batches': batches, 141 | 'serial' : s_times, 142 | 'distributed': d_times} 143 | 144 | df = pd.DataFrame(data) 145 | df.plot(x="batches", y=["serial", "distributed"], kind="bar") 146 | plt.ylabel('Times in sec', fontsize=12) 147 | plt.xlabel('Number of Batches of Images', fontsize=12) 148 | plt.grid(False) 149 | plt.show() 150 | 151 | def display_random_images(image_list: List[str], n: int=3) -> None: 152 | """ 153 | Display a grid of images, default 3 of images we want to process 154 | """ 155 | random_samples_idx = random.sample(range(len(image_list)), k=n) 156 | plt.figure(figsize=(16, 8)) 157 | for i, targ_sample in enumerate(random_samples_idx): 158 | plt.subplot(1, n, i+1) 159 | img = Image.open(image_list[targ_sample]) 160 | img_as_array = np.asarray(img) 161 | plt.imshow(img_as_array) 162 | title = f"\nshape: {img.size}" 163 | plt.axis("off") 164 | plt.title(title) 165 | plt.show() 166 | 167 | def download_images(url: str, data_dir: str) -> None: 168 | """ 169 | Given a URL and the image data directory, fetch the URL and save it in the data directory 170 | """ 171 | img_data = requests.get(url).content 172 | img_name = url.split("/")[4] 173 | img_name = f"{data_dir}/{img_name}.jpg" 174 | with open(img_name, 'wb+') as f: 175 | f.write(img_data) 176 | 177 | def insert_into_object_store(img_name:str): 178 | """ 179 | Insert the image into the object store and return its object reference 180 | """ 181 | import ray 182 | 183 | img = Image.open(img_name) 184 | img_ref = ray.put(img) 185 | return img_ref 186 | 187 | def transform_image(img_ref:object, fetch_image=True, verbose=False): 188 | """ 189 | This is a deliberate compute intensive image transfromation and tensor operation 190 | to simulate a compute intensive image processing 191 | """ 192 | import ray 193 | 194 | # Only fetch the image from the object store if called serially. 195 | if fetch_image: 196 | img = ray.get(img_ref) 197 | else: 198 | img = img_ref 199 | before_shape = img.size 200 | 201 | # Make the image blur with specified intensify 202 | # Use torchvision transformation to augment the image 203 | img = img.filter(ImageFilter.GaussianBlur(radius=20)) 204 | augmentor = T.TrivialAugmentWide(num_magnitude_bins=31) 205 | img = augmentor(img) 206 | 207 | # Convert image to tensor and transpose 208 | tensor = torch.tensor(np.asarray(img)) 209 | t_tensor = torch.transpose(tensor, 0, 1) 210 | 211 | # compute intensive operations on tensors 212 | random.seed(42) 213 | for _ in range(3): 214 | tensor.pow(3).sum() 215 | t_tensor.pow(3).sum() 216 | torch.mul(tensor, random.randint(2, 10)) 217 | torch.mul(t_tensor, random.randint(2, 10)) 218 | torch.mul(tensor, tensor) 219 | torch.mul(t_tensor, t_tensor) 220 | 221 | # Resize to a thumbnail 222 | img.thumbnail(THUMB_SIZE) 223 | after_shape = img.size 224 | if verbose: 225 | print(f"augmented: shape:{img.size}| image tensor shape:{tensor.size()} transpose shape:{t_tensor.size()}") 226 | 227 | return before_shape, after_shape 228 | 229 | --------------------------------------------------------------------------------