Skip to main content

How to Compare Runs in the MLflow UI

· 14 min read
Jagdish Kumawat
Founder @ Dewiride

Tracking runs pays off when you compare them: which settings gave the lowest error, and was the extra training time worth it? The MLflow UI gives you a runs table you can filter and sort, a chart view, and a Compare page with four plots and side-by-side tables. This guide uses all of them on four real runs, with screenshots from MLflow 3.18.0.

Syntax​

Most of this guide is clicks. The one thing you type is a query in the runs page's search box, and it follows this form:

Syntax
<prefix>.<name> <comparator> <value>
PartWhat it means
<prefix>What to filter on: metrics, params or tags
<name>The name it was logged with, such as r2 or n_estimators
<comparator>Metrics are numbers, so =, !=, >, >=, < and <= all work. Parameters and tags are stored as text, so they take =, !=, LIKE and ILIKE
<value>A number for a metric; text in quotes for a parameter or tag, such as "300"

Join conditions with and, as in metrics.r2 > 0.8 and params.max_depth = "None". OR isn't supported.

Prerequisites​

  • A tracking server with a few finished runs that logged parameters and metrics. This guide uses the four house-price runs from Part 1, Step 14 of the MLflow series; any runs with parameters and metrics work the same way.
  • The MLflow UI open in your browser: How to Open the MLflow UI and Find Your Runs.

The four runs are random forests that predict house values. They differ in two settings, the number of trees (n_estimators) and how deep each tree may grow (max_depth), and each logged three error scores: mae, rmse (lower is better) and r2 (higher is better).

Step 1: Show Metrics and Parameters as Columns​

Open the experiment, here house-price-prediction. The runs table starts with names, times and sources, not results. Click Columns:

The Columns menu of the house-price-prediction runs table in MLflow 3.18.0, with a search box and the groups Attributes (Dataset, Source and Models ticked; User, Version and Description not), Metrics (3) with mae, r2 and rmse, and Parameters (4) with max_depth, n_estimators and random_state.

The menu lists every column the runs have, in groups: Attributes, Metrics, Parameters and, further down, Tags. Tick mae, r2 and rmse under Metrics and max_depth and n_estimators under Parameters, then untick Dataset, Source and Models to make room. Each run's results now sit next to its settings:

The house-price-prediction runs table with columns for Duration, the metrics mae, r2 and rmse, and the parameters max_depth and n_estimators: 300-trees has r2 0.8062, 200-trees-depth-16 0.8033, 50-trees-depth-8 0.7388 and smiling-moose-157 0.8044.

Long numbers are cut to fit, such as 0.8062927…. The Compare page in Step 5 shows them rounded.

Step 2: Filter Runs with a Search Query​

Type a query into the search box and press Enter. To keep only the runs that explain more than 80% of the variation in house prices:

Search box
metrics.r2 > 0.8

The runs table filtered with metrics.r2 > 0.8 in the search box, leaving three runs: 300-trees, 200-trees-depth-16 and smiling-moose-157, each with an r2 above 0.80.

Three runs match; 50-trees-depth-8, with an r2 of 0.739, is gone. The ✕ in the search box clears the filter.

Each query follows the syntax at the top of this page. Here's what each one keeps from the four runs:

QueryRuns it keeps
metrics.r2 > 0.8300-trees, 200-trees-depth-16, smiling-moose-157
metrics.rmse < 0.506300-trees
params.n_estimators = "300"300-trees
metrics.r2 > 0.8 and params.max_depth = "None"300-trees, smiling-moose-157
tags.model_type = "random_forest"All four
Parameters can't use > or <

params.n_estimators > "100" doesn't filter anything: the table shows Request error with Invalid comparator '>' not one of …. The cause and the fix are in Fixed: "Invalid comparator '>' not one of" When You Search MLflow Runs by a Parameter.

Step 3: Sort by a Metric​

Keep metrics.r2 > 0.8 in the search box. Click Sort: Created and choose rmse. That sorts the highest error first, so open the menu again and click the ↑ button, Sort ascending:

The open Sort menu of the MLflow runs table with a search box, the Sort descending and Sort ascending arrow buttons, and the sort options Created, User, Run Name, Source, Version, Description, mae, r2, rmse (ticked), max_depth, n_estimators and random_state.

The best run is now on top:

The filtered runs table sorted by rmse from lowest to highest: 300-trees at 0.5038, smiling-moose-157 at 0.5062 and 200-trees-depth-16 at 0.5075, with the button reading Sort: rmse.

Clicking a column header, such as rmse, also sorts by that column.

Step 4: See the Runs as Charts​

Click the chart icon, the second button left of the search box. Each metric becomes a bar chart with one bar per run, in the run's color:

The chart view of the runs page with bar charts for mae, r2 and rmse, one bar per run, where 50-trees-depth-8 has the longest error bars and the shortest r2 bar.

The odd one out is easy to spot: 50-trees-depth-8 has the longest error bars and the shortest r2 bar. The first icon brings the table back.

Step 5: Select Runs and Open the Compare Page​

Back in the table, clear the search and tick the runs to compare. The box in the header row ticks them all. The toolbar changes to Rename, Delete, Compare and Add tags:

The MLflow runs table with all four runs ticked and the toolbar showing Rename greyed out, Delete, Compare and Add tags, above the runs with their duration, mae, r2, rmse, max_depth and n_estimators.

With one run ticked, Compare is greyed out, because a comparison needs at least two; with all four ticked, Rename is. Delete sits right next to Compare, so click carefully. Click Compare.

Step 6: Read the Parallel Coordinates Plot​

The page is titled Comparing 4 Runs from 1 Experiment, with four plots under Visualizations. The first one, the Parallel Coordinates Plot, shows every run's settings and result at once:

The Comparing 4 Runs from 1 Experiment page on the Parallel Coordinates Plot tab, with axes for max_depth, n_estimators and mae: three blue lines end at low mae values near 0.33, and one red line runs from max_depth 8 through 50 trees to the highest mae, 0.403.

  • Each line is one run. It crosses one axis per parameter, here max_depth and n_estimators, and ends on the metric, here mae.
  • The color comes from the metric: dark blue for the lowest error, red for the highest. The one red line is 50-trees-depth-8: depth 8, 50 trees, an mae of 0.403.
  • The Parameters and Metrics boxes choose the axes. Clear All empties them.

Step 7: Plot One Setting Against a Result​

Open the Scatter Plot tab and choose n_estimators for the X-axis and rmse for the Y-axis:

The Comparing 4 Runs page on the Scatter Plot tab with n_estimators on the X-axis and rmse on the Y-axis: 50 trees at about 0.585, and 100, 200 and 300 trees all near 0.505.

Each dot is a run. The 50-tree run, which was also limited to a depth of 8, sits far above the rest; 100, 200 and 300 trees all land near 0.505.

Step 8: Try the Box and Contour Plots​

The Box Plot groups runs that share a parameter value. Choose max_depth for the X-axis and rmse for the Y-axis:

The Box Plot tab with max_depth on the X-axis and rmse on the Y-axis: a green box for None near 0.505 built from two runs, an orange line for 16 at about 0.508, and a blue line for 8 at about 0.585, with a legend for 8, 16 and None.

Each max_depth value gets a box in the legend's color. With only one or two runs per value, the boxes are thin; the plot becomes useful when many runs share each value, as in a hyperparameter search.

The Contour Plot draws a result over two numeric settings. With these four runs, it shows a message instead of a plot:

The Contour Plot tab with n_estimators on the X-axis, random_state on the Y-axis and mae on the Z-axis, and the message: The Y axis doesn't have enough unique data points to render the contour plot.

The Y axis doesn't have enough unique data points to render the contour plot. The contour needs at least two different values on each axis, and random_state is 42 in every run. Its lists only offer values that are numbers in every run, so max_depth, which is None in two runs, isn't there either. That leaves n_estimators as the only setting that changes, and a contour of a result over two settings needs two. A search over two numeric settings, such as a grid search, gives it what it needs.

Step 9: Read the Tables and Show Only the Differences​

Below the plots, the page lists the runs side by side: Run details (ID, name, start, end and duration), Parameters, Metrics, Artifacts and Tags:

The tables of the Compare page: Run details with each run's ID, name, start and end time and duration, Parameters with max_depth and n_estimators highlighted because they differ and random_state 42 and test_size 0.2 the same in every run, and Metrics with mae, r2 and rmse rounded to three decimals.

Rows whose values differ are highlighted: max_depth and n_estimators. Turn on Show diff only above the Parameters table to hide the rows that are the same in every run:

The Parameters table on the Compare page with Show diff only switched on, showing only max_depth (None, 16, 8, None) and n_estimators (300, 200, 50, 100).

random_state and test_size are hidden. That they're the same everywhere matters too: every run was scored on the same test rows, so the scores are comparable. Metrics and Tags have their own Show diff only switch.

The bottom of the Compare page: the Artifacts section saying No common artifacts to display, and the Tags section with a Show diff only switch and the tags dataset california_housing and model_type random_forest for all four runs.

Artifacts says No common artifacts to display., although every run logged the same chart. In MLflow 3.18.0 this section only lists files at the top level of every run's artifacts, and Part 1 saved its chart inside a plots folder. To look at the charts, open each run's Artifacts tab.

Compare Runs in Python​

mlflow.search_runs() runs the same kind of query from code and returns a pandas table. Create compare_runs.py in a project that has MLflow installed:

compare_runs.py
import mlflow

mlflow.set_tracking_uri("http://127.0.0.1:8080")

runs = mlflow.search_runs(
experiment_names=["house-price-prediction"],
filter_string="metrics.r2 > 0.8",
order_by=["metrics.rmse ASC"],
)
columns = ["tags.mlflow.runName", "params.n_estimators", "params.max_depth", "metrics.rmse", "metrics.r2"]
print(runs[columns].to_string(index=False))
  • filter_string takes the same queries as the search box.
  • order_by sorts; ASC puts the lowest rmse first.
  • The result has one row per run, with columns named params.…, metrics.… and tags.…. The run's name is in tags.mlflow.runName.
Terminal
uv run python compare_runs.py
Output
tags.mlflow.runName params.n_estimators params.max_depth metrics.rmse metrics.r2
300-trees 300 None 0.503821 0.806293
smiling-moose-157 100 None 0.506261 0.804412
200-trees-depth-16 200 16 0.507588 0.803385

The same three runs, in the same order as the sorted table in Step 3.

What the Comparison Shows​

  • 50-trees-depth-8 is clearly worse: the highest errors in every view.
  • More than 100 trees barely helps: 100, 200 and 300 trees all land near 0.505 RMSE.
  • But it costs time: the Run details table shows 4.1 seconds for 300 trees against 1.6 seconds for 100.

So the 100-tree forest, smiling-moose-157, gives nearly the best score in well under half the time.

Common Mistakes​

MistakeWhat happensDo this instead
Comparing runs with the default columnsYou see names and times, not resultsAdd metric and parameter columns (Step 1)
Using > or < on a parameterRequest error with Invalid comparator '>' not one of …Use = or != on parameters, or filter in Python
Comparing runs scored on different test dataThe scores can't be compared fairlyCheck that test_size and random_state match in the Parameters table

Troubleshooting​

SymptomLikely causeFix
Compare is greyed outFewer than two runs are tickedTick at least two runs
A run is missing from the tableA search filter is still appliedClear the search box with ✕
The Y axis doesn't have enough unique data points to render the contour plot.The chosen parameter has the same value in every runPick numeric parameters that change between runs
No common artifacts to display.The files sit inside folders, or the runs don't share a fileOpen each run's Artifacts tab

FAQ​

Can I bookmark a comparison?​

Yes. The Compare page's address lists the run IDs, so opening it again brings back the same comparison.

Why are the numbers rounded on the Compare page?​

The Compare page's tables show three decimals. The runs table shows more digits but cuts them to fit the column.

Does comparing runs change them?​

No. Filtering, sorting and the Compare page only read the runs.

Conclusion​

The runs table compared the four forests once their metrics and parameters were columns: metrics.r2 > 0.8 left three, and sorting by rmse put 300-trees first. The Compare page's parallel coordinates and scatter plots showed that more than 100 trees barely helped, and Show diff only confirmed that only max_depth and n_estimators changed. mlflow.search_runs() gave the same answer from Python.

Additional Resources​