What you will be able to do
- Decide when to stay on one larger machine and when to scale out across nodes
- Tell data parallelism, model parallelism and task parallelism apart, and name the Databricks tool that fits each
- Choose between Spark and Ray for a training workload, or combine them
- Use groupBy().applyInPandas() for per-group work and mapInPandas() for batch transforms such as inference
- Run a distributed Optuna study on Spark executors with MlflowSparkStudy and MlflowStorage so every trial is tracked in MLflow
Key concept
Data parallelism vs. task parallelism — Data parallelism runs one operation over every slice of a large dataset, which is where Spark is strongest. Task parallelism runs many independent jobs at once, such as trials, simulations or separate models, which is where Ray is strongest. Most scaling decisions on Databricks come down to working out which of the two your workload is.
1.Vertical first: why Databricks starts you on one machine
You can scale a training workload in two ways. Vertical scaling means moving it to a bigger single machine. Horizontal scaling means spreading it across several machines. Databricks recommends a default: when possible, train neural networks on a single machine. Distributed code is harder to write and debug, and the workers have to exchange gradients, parameters or data over the network. That traffic is overhead a single machine never pays.
The reason to scale horizontally is size, not impatience. Databricks says to consider distributed training and inference when your model or your data is too large to fit in memory on one machine. If a job already fits comfortably on one node, buying a larger instance or simply waiting is usually the better trade than adding nodes. When a job really has outgrown one machine, Databricks Runtime ML ships three options: TorchDistributor, the DeepSpeed distributor and Ray. TorchDistributor is an open-source PySpark module that launches PyTorch training jobs as Spark jobs. It sets up the communication channels between workers and runs torch.distributed.run across the worker nodes.
Checkpoint 1 of 6· Check yourself
Which situation does Databricks name as the reason to move from single-machine to distributed training?
The documented trigger is memory: the model or the data no longer fits on one machine. Long runtimes and idle nodes are not the documented trigger.
“you should consider distributed training and inference if your model or your data are too large to fit in memory on a single machine”Source: docs.databricks.com
Checkpoint 2 of 6· Exam question
A team is training a moderately sized neural network whose parameters comfortably fit on one GPU, but they want to cut wall-clock training time by processing more samples per step across multiple GPUs. Which parallelization strategy fits this goal?
Correct answer: A — Data parallelism, replicating the model on each GPU and splitting each batch across devices so gradients are computed in parallel and averaged.
- A. Correct: since the model already fits on one device, replicating it and splitting batches across GPUs (data parallelism) increases per-step throughput and reduces wall-clock time without needing to fragment the model.
- B. Model parallelism is aimed at models too large for one device's memory; applying it here adds cross-device coordination overhead without addressing the team's actual goal of processing more samples per step.
- C. A single bigger GPU can speed up one replica but does not add the extra concurrent compute of several devices working on different batch shards simultaneously, so it caps the throughput gain versus multi-GPU data parallelism.
- D. GPU devices are the normal target for data-parallel and pipeline-parallel training; restricting batch-splitting strategies to CPUs ignores the GPUs the team already has available.
Sources1
2.Splitting the data or splitting the model
After you decide to scale out, the next question is what gets split. In data parallelism, every worker holds a full copy of the model and processes a different slice of the data. Distributed Data Parallel (DDP) is the standard example. The full model is replicated on each GPU and the data batches are split across the GPUs. This only works if the model fits on one device. Adding workers then increases throughput.
Once the model itself outgrows a single device's memory, you need a strategy that spreads the model across devices. Databricks points you to FSDP or DeepSpeed for this case. The DeepSpeed distributor is built on top of TorchDistributor. Databricks recommends it for models that need more compute but are limited by memory, because it offers optimized memory usage, reduced communication overhead and advanced pipeline parallelism.
| Situation | Strategy | Databricks tooling named in the docs |
|---|---|---|
| Model fits on one GPU; you want more data throughput | Data parallelism (DDP: full model replicated on each GPU, batches split) | TorchDistributor running PyTorch DDP |
| Model too large for one GPU's memory | Model-sharding / pipeline parallelism | FSDP or the DeepSpeed distributor |
| Large tabular dataset, classic ML algorithms | Data parallelism across Spark executors | Spark ML via pyspark.ml.connect |
Checkpoint 3 of 6· Check yourself
A team's model trains well under DDP on small GPUs but now runs out of GPU memory after the architecture grew. Which change matches Databricks guidance?
DDP replicates the whole model on every GPU, so adding GPUs never fixes a model that doesn't fit on one. DeepSpeed is the recommended route for memory-bound models.
“a recommended solution for customers with models that require higher compute power, but are limited by memory constraints”Source: docs.databricks.com
3.Spark or Ray for distributing the work
Databricks runs Spark and Ray in the same execution environment, so you rarely have to pick just one. What you do need to know is which kinds of work each engine is built for. Spark is optimized for large-scale data processing such as joins, filters, aggregations, ETL and feature engineering, and its MLlib and Spark ML libraries are built for large-scale ML algorithms. Ray is built for task parallelism: many independent, compute-heavy tasks running at once. Databricks lists the workloads where Spark is less optimized and Ray is the better fit. They include reinforcement learning, hierarchical time series forecasting, simulation modeling, hyperparameter search, deep learning training and HPC.
| Dimension | Spark | Ray |
|---|---|---|
| Core strength | Data parallelism: the same operation on each element of a large dataset | Task parallelism: independent tasks run concurrently |
| Typical ML work | MLlib / Spark ML algorithms, feature engineering, preprocessing | Hyperparameter search, deep learning training, reinforcement learning, simulation |
| Role in a combined pipeline | Data retrieval, input/output, writing to Unity Catalog tables | Heavy computation stages |
For a single task that uses both engines, the main pattern Databricks recommends is Spark for data handling and Ray for computation. Spark reads the data. databricks.ray.data.from_spark passes it to Ray Data. The resulting model is saved to MLflow, or the output data to Unity Catalog tables. Two advanced patterns are also documented: running Ray inside Spark functions such as UDFs, and running Spark and Ray operations concurrently. You can also put the ETL step in its own Databricks Workflow subtask, so each step gets a cluster type that suits it and the two engines don't compete for resources.
Checkpoint 4 of 6· Match them up
Match each workload to the engine and the reason Databricks gives for it
Tap a term, then the definition that fits it.
Spark is the choice for data-parallel processing. Ray is the choice for compute-heavy work made of independent tasks, which is where Spark is less optimized.
“such as reinforcement learning, hierarchical time series forecasting, simulation modeling, hyperparameter search, deep learning training, and high-performance computing (HPC)”Source: docs.databricks.com
Sources3
4.pandas function APIs: per-group training and batch inference
For classic ML on large tables, pyspark.ml.connect provides distributed training and inference for Spark ML models. In Databricks Runtime 17.0 and above, Spark ML is enabled by default on Standard compute. Many teams, though, need to train many small single-node models, such as one per store or one per device. pandas function APIs handle that case. They apply a native Python function that takes and returns pandas objects to a PySpark DataFrame. Like pandas UDFs, they use Apache Arrow to move the data, and Python type hints are optional.
groupBy().applyInPandas() follows the split-apply-combine pattern. Spark splits the rows by key, calls your function once per group with a pandas.DataFrame that contains all the rows and columns for that group, and combines the returned DataFrames. You must supply the function and an output schema. The documentation's example subtracts a group mean rather than training a model, and it shows no per-group training example. The contract is the same either way, though: each function call sees one complete group, which is what per-group model fitting needs.
Checkpoint 5 of 6· Fill the gap
Which method completes this per-group transformation?
def subtract_mean(pdf):
# pdf is a pandas.DataFrame
v = pdf.v
return pdf.assign(v=v - v.mean())
df.groupby("id"). ? (subtract_mean, schema="id long, v double").show()Grouped map uses groupBy().applyInPandas() with a function and an output schema. mapInPandas works on a whole DataFrame, not on grouped data.
Source: docs.databricks.comThat design has a cost. All of a group's data is loaded into memory before the function runs, and maxRecordsPerBatch does not apply to groups. If the keys are skewed, one very large group can cause an out-of-memory error, so it is up to you to make sure each group fits. For inference you usually don't need grouping. DataFrame.mapInPandas() passes your function an iterator of pandas DataFrames, and the function yields DataFrames back. The output can be any length. The third API type, cogrouped map, pairs the groups of two DataFrames that share a key.
df = spark.createDataFrame([(1, 21), (2, 30)], ("id", "age"))
def filter_func(iterator):
for pdf in iterator:
yield pdf[pdf.id == 1]
df.mapInPandas(filter_func, schema=df.schema).show()5.Distributed hyperparameter tuning with Optuna and MLflow
Hyperparameter search is a task-parallel job: each trial is independent, so many can run at once. Optuna is an open-source Python library for hyperparameter tuning that can be scaled horizontally across multiple compute resources. MLflow 3.0 integrates with it through two classes. MlflowStorage lets Optuna use the MLflow Tracking Server as its storage backend, which gives all the workers one shared place to record trials. MlflowSparkStudy launches parallel Optuna studies using PySpark executors.
The workflow has four steps. First, define an objective function. Inside it you define the search space with trial.suggest_* methods such as suggest_float, suggest_int and suggest_categorical, and you return the value to optimize, such as the validation error. Second, create shared storage with MlflowStorage(experiment_id=...). Third, create an MlflowSparkStudy with a study name and that storage. Fourth, call optimize with the objective, the number of trials and n_jobs. By default the study uses optuna.samplers.TPESampler and optuna.pruners.MedianPruner. MLflow 3.0 is pre-installed in Databricks Runtime 17.0 ML and above. On older runtimes you install the latest MLflow and Optuna with %pip.
This is also the current answer where you might once have used Hyperopt with SparkTrials. Hyperopt is not included in Databricks Runtime ML after 16.4 LTS ML. Databricks recommends Optuna, or Ray Tune for a similar experience to the deprecated Hyperopt distributed tuning.
from mlflow.pyspark.optuna.study import MlflowSparkStudy
mlflow_study = MlflowSparkStudy(
study_name="spark-mlflow-tuning",
storage=mlflow_storage,
)
mlflow_study.optimize(objective, n_trials=8, n_jobs=4)Checkpoint 6 of 6· Check yourself
What role does MlflowStorage play in a distributed Optuna study on Databricks?
MlflowStorage is the shared storage backend backed by the MLflow Tracking Server. Launching parallel studies is the job of MlflowSparkStudy.
“MlflowStorage class allows Optuna to use the MLflow Tracking Server as its storage backend.”Source: docs.databricks.com
Exam traps
Each one states something that sounds right. Open it to see what is actually true.
1.Adding worker nodes always speeds up a training job.Why is that wrong?
Distributed training adds complexity and communication overhead. Databricks recommends a single machine unless the model or data no longer fits in memory.
Covered in Vertical first: why Databricks starts you on one machine
2.Setting maxRecordsPerBatch keeps a skewed group in applyInPandas from running out of memory.Why is that wrong?
A whole group is loaded into memory before the function runs, and maxRecordsPerBatch is not applied to groups. Keeping each group small enough to fit is your job.
Covered in pandas function APIs: per-group training and batch inference
3.Distributed tuning on current Databricks Runtime ML should use Hyperopt with SparkTrials.Why is that wrong?
Hyperopt is no longer included after 16.4 LTS ML. Databricks recommends Optuna, or Ray Tune for a similar experience to the deprecated Hyperopt distributed tuning.
Covered in Distributed hyperparameter tuning with Optuna and MLflow
Sources
Every claim above is drawn from one of these pages, quoted as it was written on the date shown.
- 1.
“distributed code for training and inference is more complex than single-machine code and slower due to communication overhead”
↩︎ Vertical first: why Databricks starts you on one machine“it lets you launch PyTorch training jobs as Spark jobs”
↩︎ Vertical first: why Databricks starts you on one machine“offers optimized memory usage, reduced communication overhead, and advanced pipeline parallelism”
↩︎ Splitting the data or splitting the model“In Databricks Runtime 17.0 and above, Spark ML is enabled by default in Standard compute resources”
↩︎ pandas function APIs: per-group training and batch inference“When possible, Databricks recommends that you train neural networks on a single machine”
↩︎ Exam trap 1“you should consider distributed training and inference if your model or your data are too large to fit in memory on a single machine”
↩︎ Checkpoint“a recommended solution for customers with models that require higher compute power, but are limited by memory constraints”
↩︎ Checkpoint - 2.
“where the full model is replicated on each GPU and data batches are split across GPUs”
↩︎ Splitting the data or splitting the model“consider FSDP or DeepSpeed instead”
↩︎ Splitting the data or splitting the model - 3.
“Ray excels at task parallelism - Run a set of independent tasks concurrently.”
↩︎ Spark or Ray for distributing the work“use databricks.ray.data.from_spark to pass training data from Spark to Ray Data”
↩︎ Spark or Ray for distributing the work“Spark excels at data parallelism - Apply the same operation to each element of a large dataset.”
↩︎ Key concept“such as reinforcement learning, hierarchical time series forecasting, simulation modeling, hyperparameter search, deep learning training, and high-performance computing (HPC)”
↩︎ Checkpoint - 4.
“The input data contains all the rows and columns for each group.”
↩︎ pandas function APIs: per-group training and batch inference“All data for a group is loaded into memory before the function is applied.”
↩︎ pandas function APIs: per-group training and batch inference“It can return output of arbitrary length in contrast to some pandas UDFs such as Series to Series.”
↩︎ pandas function APIs: per-group training and batch inference“The configuration for maxRecordsPerBatch is not applied on groups”
↩︎ Exam trap 2 - 5.
“MlflowStorage class allows Optuna to use the MLflow Tracking Server as its storage backend.”
↩︎ Distributed hyperparameter tuning with Optuna and MLflow“MlflowSparkStudy class enables launching parallel Optuna studies using PySpark executors.”
↩︎ Distributed hyperparameter tuning with Optuna and MLflow“MLflow 3.0 is pre-installed in Databricks Runtime 17.0 ML and above.”
↩︎ Distributed hyperparameter tuning with Optuna and MLflow - 6.
“Hyperopt is not included in Databricks Runtime for Machine Learning after 16.4 LTS ML.”
↩︎ Distributed hyperparameter tuning with Optuna and MLflow“Hyperopt is not included in Databricks Runtime for Machine Learning after 16.4 LTS ML.”
↩︎ Exam trap 3