Record your own Python runs with MLflow on CloudFerro Cloud
Once the first example has saved a result successfully, the next step may be to record something from your own Python program. That means deciding which inputs, measurements, and output files will help you understand or compare its executions.
An average calculation provides a small example of the MLflow calls that send those records to AI Experiments. You can then replace the calculation with your own processing or training code while keeping the connection, sign-in, and run structure.
Prerequisites
No. 1 A running instance with access to its artifact bucket
Use an AI Experiments instance with status Running, membership for your account, and permission to create an experiment or write to one you own. For instance creation and membership instructions, follow the article Your first AI Experiments instance on CloudFerro Cloud. The article Object storage for AI Experiments on CloudFerro Cloud covers the bucket connection used to store reports. Have the instance’s tracking URL ready and confirm that its MLflow UI opens.
No. 2 The example folder and Python environment
Prepare ~/ai-experiments-hello-world with Python 3.10 or newer, an active .venv, MLflow 3.14.0, and requests. In the article Python code for your first MLflow run on CloudFerro Cloud, Prerequisite No. 2 gives the folder creation, installation, and download commands. Keep get_token.py in this folder; the new program imports the same helper.
No. 3 A configured and authenticated client
Follow the article Connect Python and the CLI to AI Experiments on CloudFerro Cloud to set MLFLOW_TRACKING_URI, MLFLOW_USERNAME, and MLFLOW_PASSWORD, then check the CLI connection. Keep that terminal open and your two-factor authentication app ready. The new program requests a fresh token when it starts, using the same sign-in method as the first example.
Which code sends the results?
In first_experiment.py, these calls select and send the input numbers, their total, and a report:
mlflow.log_param("numbers", json.dumps(args.numbers))
mlflow.log_metric("total", total)
mlflow.log_text(
json.dumps({"numbers": args.numbers, "total": total}, indent=2),
"result.json",
)
The MLflow client handles the requests needed to save these records. A Python calculation or print() statement alone does not send its result to the instance. Your logging calls decide which values and files become part of a run.
Call |
Use it for |
Where to find the result |
|---|---|---|
mlflow.log_param() |
Input settings, such as numbers or a learning rate. |
Parameters on the run’s Overview page. |
mlflow.log_metric() |
Numerical measurements, such as an average, accuracy, or duration. |
Metrics on the run’s Overview page. |
mlflow.log_text() |
Text prepared in memory, such as a JSON report. |
A file under the run’s Artifacts tab. |
mlflow.log_artifact() |
An existing file produced by your code, such as a CSV or PNG. |
A file under the run’s Artifacts tab. |
Parameters and metrics are stored in the tracking database. Artifact files use the storage configured for the instance. With this instance setup, your Python program uses the MLflow connection; the bucket’s endpoint and keys were supplied when creating the instance.
Step 1: Save the new program
In the configured terminal, return to the example folder and activate its environment if necessary:
cd "$HOME/ai-experiments-hello-world"
source .venv/bin/activate
Download my_experiment.py into this folder, beside get_token.py. Keep first_experiment.py as the original addition example. The new file contains:
"""Calculate an average and record the inputs, result, and report in MLflow."""
import argparse
import json
import os
import mlflow
from get_token import get_token
def main() -> None:
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("--numbers", nargs="+", type=int, default=[10, 20, 30])
parser.add_argument("--experiment", default="my-experiments")
parser.add_argument("--run-name", default="calculate-average")
args = parser.parse_args()
tracking_uri = os.environ.get("MLFLOW_TRACKING_URI", "").strip()
if not tracking_uri:
raise SystemExit("Set MLFLOW_TRACKING_URI to your instance URL first.")
# Select the instance and authenticate before making tracking requests.
mlflow.set_tracking_uri(tracking_uri)
os.environ["MLFLOW_TRACKING_TOKEN"] = get_token()
mlflow.set_experiment(args.experiment)
with mlflow.start_run(run_name=args.run_name) as run:
# Replace this calculation with your own processing code.
average = sum(args.numbers) / len(args.numbers)
# Choose the inputs, numerical results, and files to record.
mlflow.log_param("numbers", json.dumps(args.numbers))
mlflow.log_metric("average", average)
mlflow.log_text(
json.dumps({"numbers": args.numbers, "average": average}, indent=2),
"result.json",
)
print(f"Average: {average}")
print(f"Run ID: {run.info.run_id}")
if __name__ == "__main__":
main()
The connection lines have separate jobs. mlflow.set_tracking_uri() selects the instance URL, while get_token() obtains the token assigned to MLFLOW_TRACKING_TOKEN. These settings are applied before mlflow.set_experiment() selects my-experiments, creating it if needed.
The with mlflow.start_run(…) block groups the calculation and logging calls into one run. Leaving the block normally marks the run as finished. The average is calculated locally; the three logging calls then record the inputs, average, and result.json report.
Step 2: Run and inspect your example
Run the downloaded program from the same configured terminal:
python my_experiment.py
Enter a fresh TOTP code when prompted. After logging succeeds, the output includes:
Average: 20.0
Run ID: <generated run ID>
In the MLflow UI, select Model training, open Experiments → my-experiments, and click the calculate-average run name. On Overview, check that the numbers parameter is [10, 20, 30] and the average metric is 20.0. Then open Artifacts → result.json and check the report:
{
"numbers": [10, 20, 30],
"average": 20.0
}
Step 3: Compare a second execution
Add another input and give the next run a different name:
python my_experiment.py --numbers 10 20 30 40 --run-name average-four-numbers
Enter a fresh TOTP code. The average is now 25.0, and the program prints a different run ID. Refresh my-experiments → Runs, select both runs, and open the comparison view:
Run name |
Parameter: numbers |
Metric: average |
|---|---|---|
calculate-average |
[10, 20, 30] |
20.0 |
average-four-numbers |
[10, 20, 30, 40] |
25.0 |
Both runs belong to the same MLflow experiment, my-experiments, and keep separate result.json artifacts. The two averages check that different inputs and results were recorded correctly; a higher average does not indicate a better model. A new invocation starts a new run, even if you reuse a run name; use the run ID to identify a specific execution. To use another experiment, pass –experiment with the same name for both commands.
Step 4: Adapt the program to your work
Keep the connection and authentication lines, then change the code inside the run block:
Replace the average calculation with your processing or training code. Keep it inside with mlflow.start_run(…) so it belongs to the same tracked execution.
Record the input settings you want to compare with mlflow.log_param(). Use short values, such as a threshold or a dataset identifier; save a full input file as an artifact if you need to retain it.
Record each numerical result with mlflow.log_metric(), choosing a descriptive name such as accuracy, duration_seconds, or average. Keep the same metric name and units across runs you want to compare.
Update the JSON report and the final print() statement to match the values your code calculates. The report is saved by mlflow.log_text(); printing a value only displays it in the terminal.
Treat a parameter as a fixed setting for a run. When comparing a different setting, start a new run as in Step 3. A metric can record repeated measurements, such as loss at successive training steps, by supplying the step argument to mlflow.log_metric().
Save a file produced by your program
To also record a CSV report, add import csv alongside the imports at the top of my_experiment.py. Insert the following code inside the existing run block, after the average calculation, using the same indentation as the logging calls:
with open("report.csv", "w", newline="", encoding="utf-8") as report:
writer = csv.writer(report)
writer.writerow(["count", "average"])
writer.writerow([len(args.numbers), average])
mlflow.log_artifact("report.csv")
The with open(…) block writes and closes report.csv in your working folder. mlflow.log_artifact() then uploads that file as an artifact of the active run. Run the modified program with a new name:
python my_experiment.py --run-name average-with-csv
For the default inputs, the local file contains:
count,average
3,20.0
Open average-with-csv → Artifacts to find both report.csv and result.json. Each later execution replaces the local report.csv, while the copy already uploaded to an earlier run remains attached to that run. The same logging call can upload a plot or another output file after your code has finished writing it.
What to do next
For more detail on comparisons in the web UI, follow the article Run and compare your first MLflow runs on CloudFerro Cloud. If authentication or logging fails, use the article Troubleshooting AI Experiments on CloudFerro Cloud to check the error. An artifact upload failure can leave earlier parameters and metrics recorded, so check the terminal’s final output as well as the run page.
The MLflow Python API reference describes additional logging functions and their arguments. MLflow also offers automatic logging for supported machine-learning libraries. That feature requires a supported integration and explicit configuration; the arithmetic examples here use the logging calls shown above.