CertSafari
    Databricks Certified Machine Learning Professional· Lessons

    Domain 1 · Lesson 2/11

    Scaling ML Training on Databricks: Single Node, Spark, Ray and pandas Function APIs

    Scaling and Tuning

    12 min read
    9.09% of exam
    6 sources
    Published 3 Oct 2026
    Docs as of 30 Sep 2026

    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?

    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?

    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.

    Choosing a parallelism strategy by what doesn't fit
    SituationStrategyDatabricks tooling named in the docs
    Model fits on one GPU; you want more data throughputData parallelism (DDP: full model replicated on each GPU, batches split)TorchDistributor running PyTorch DDP
    Model too large for one GPU's memoryModel-sharding / pipeline parallelismFSDP or the DeepSpeed distributor
    Large tabular dataset, classic ML algorithmsData parallelism across Spark executorsSpark 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?

    Sources21

    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.

    Spark vs. Ray on Databricks
    DimensionSparkRay
    Core strengthData parallelism: the same operation on each element of a large datasetTask parallelism: independent tasks run concurrently
    Typical ML workMLlib / Spark ML algorithms, feature engineering, preprocessingHyperparameter search, deep learning training, reinforcement learning, simulation
    Role in a combined pipelineData retrieval, input/output, writing to Unity Catalog tablesHeavy 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.

    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()

    That 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.

    mapInPandas: a function that takes an iterator of pandas DataFrames and yields DataFramespython
    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()

    Sources41

    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.

    Run parallel Optuna trials on Spark executors with MLflow-backed storagepython
    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?

    Sources56

    Exam traps

    Each one states something that sounds right. Open it to see what is actually true.

    1. 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. 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. 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. 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. 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. 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. 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. 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. 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

    Continue to page 2 of 2

    Distributed Hyperparameter Tuning on Databricks: Optuna with MLflow and Ray Tune

    Spotted a mistake, or was something unclear? Tell us.