<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" version="2.0">
  <channel>
    <title>article Train and Deploy YOLO Vision Model on Databricks AI Runtime (AIR) in Technical Blog</title>
    <link>https://community.databricks.com/t5/technical-blog/train-and-deploy-yolo-vision-model-on-databricks-ai-runtime-air/ba-p/151558</link>
    <description>&lt;H2&gt;&lt;STRONG&gt;&lt;A id="intro" target="_blank"&gt;&lt;/A&gt;Introduction&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;A href="https://docs.ultralytics.com/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Ultralytics YOLO&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;&lt;A href="#ultralytics-licensing" target="_self"&gt;&lt;SUP&gt;*&lt;/SUP&gt;&lt;/A&gt; (You Only Look Once) is one of the most widely used &lt;/SPAN&gt;&lt;STRONG&gt;computer vision frameworks&lt;/STRONG&gt;&lt;SPAN&gt;. It is fast, accurate, and well supported, with a range of model sizes (from nano to extra-large) so you can trade off speed and accuracy for edge or server deployment. Training and inference are straightforward with a Python API and practical documentation, and the ecosystem features readily available pretrained weights, support for standard datasets (e.g. &lt;/SPAN&gt;&lt;A href="https://cocodataset.org/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;COCO&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;), and ongoing active model development, as exemplified by recent advancements in &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/models/yolo11/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;YOLO11&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;For teams adopting computer vision (CV) tasks on Databricks, &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Ultralytics YOLO&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; is a practical choice for both prototyping and production pipelines. The framework supports multiple CV tasks — &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/tasks/detect/" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;object detection&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/tasks/classify/" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;classification&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/tasks/segment/" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;segmentation&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/tasks/pose/" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;pose estimation&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt;, and &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/tasks/obb/" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;oriented bounding boxes (OBB)&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt; — each with models in several sizes (nano to extra-large, often denoted as &lt;/SPAN&gt;&lt;SPAN&gt;n&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;s&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;m&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;l&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;x&lt;/SPAN&gt;&lt;SPAN&gt;).&lt;/SPAN&gt;&lt;/P&gt;
&lt;P class="lia-align-center"&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mmt_0-1781055272540.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/27680i4FFA6D3D7A180B94/image-size/large?v=v2&amp;amp;px=999" role="button" title="mmt_0-1781055272540.png" alt="mmt_0-1781055272540.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P class="lia-align-center"&gt;&lt;I&gt;&lt;SPAN&gt;Figure 1: Common computer vision tasks and their associated annotation type.&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;This post demonstrates a single-node workflow for training an &lt;/SPAN&gt;&lt;STRONG&gt;object detection&lt;/STRONG&gt;&lt;SPAN&gt; model on &lt;/SPAN&gt;&lt;A href="https://www.databricks.com/blog/introducing-ai-runtime-scalable-serverless-nvidia-gpus-databricks-training-and-finetuning" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Databricks AI Runtime&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; — scalable, serverless NVIDIA GPU compute. We use the nano YOLO model, &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/models/yolo11/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;YOLO11n&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;, for real-time performance that outputs bounding boxes, class labels, and confidence scores. The process covers training YOLO11n on the &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/datasets/detect/coco128/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;COCO128&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; dataset (&lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;demo-only&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt;; refer to &lt;/SPAN&gt;&lt;STRONG&gt;Data preparation&lt;/STRONG&gt;&lt;SPAN&gt; for production guidance) and deploying it to &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/machine-learning/model-serving/index.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Model Serving&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;. Deployment includes a &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#creating-custom-pyfunc-models" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;custom MLflow PyFunc wrapper&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; to handle base64 image input to the YOLO model and structured bounding-box output from model prediction.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;Why AI Runtime and single-node?&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Critically, running YOLO on &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/aws/en/machine-learning/ai-runtime" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Databricks AI Runtime&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; lets you train and iterate &lt;/SPAN&gt;&lt;STRONG&gt;without provisioning or managing clusters&lt;/STRONG&gt;&lt;SPAN&gt;: you get GPU compute on demand, pay for what you use, and when you are done the compute is terminated. This makes it ideal for experimentation, proof-of-concept, and small-to-medium training jobs — and &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/mlflow/index.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;MLflow&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/connect/unity-catalog/volumes.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Unity Catalog&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; keep experiments and artifacts organized.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;STRONG&gt;Single-node&lt;/STRONG&gt;&lt;SPAN&gt; (one GPU instance) keeps the workflow simple and sufficient for many object-detection use cases. YOLO11n is a small model; training on datasets in the low thousands to tens of thousands of images often fits comfortably on one GPU (e.g. A10). A single node avoids distributed-training setup, multi-worker debugging, and extra cost — so you can focus on data, labels, and the MLflow-to-serving path.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;When your dataset or model grows and training time becomes a bottleneck, you can move to multi-GPU or multi-node patterns; the same registration and deployment steps in this post still apply.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;What you'll need to get started&lt;/STRONG&gt;&lt;/H2&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Workspace:&lt;/STRONG&gt;&lt;SPAN&gt; AI Runtime with access to an &lt;/SPAN&gt;&lt;STRONG&gt;AI&lt;/STRONG&gt;&lt;SPAN&gt; base environment (Serverless GPU).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Permissions:&lt;/STRONG&gt;&lt;SPAN&gt; Create schemas and volumes in Unity Catalog; run MLflow experiments; register models; create Model Serving endpoints.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Notebook:&lt;/STRONG&gt;&lt;SPAN&gt; From the &lt;/SPAN&gt;&lt;A href="https://github.com/databricks-industry-solutions/cv-playground" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;cv-playground&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; repository — e.g. &lt;/SPAN&gt;&lt;A href="https://github.com/databricks-industry-solutions/cv-playground/blob/main/projects/ultralytics_databricks_examples/air-yolo11n-detect-coco128-singleGPU.ipynb" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;air-yolo11n-detect-coco128-singleGPU.ipynb&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN&gt;Add the notebook via &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/notebooks/notebook-export-import.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Import a notebook&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; or &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/repos/repos-setup.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Clone a Git repo (Repos)&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;, then attach to Serverless GPU.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Navigate to the &lt;/SPAN&gt;&lt;STRONG&gt;Compute&lt;/STRONG&gt;&lt;SPAN&gt; dropdown, &lt;/SPAN&gt;&lt;STRONG&gt;Connect&lt;/STRONG&gt;&lt;SPAN&gt; to and configure the notebook AI Runtime. Within the &lt;/SPAN&gt;&lt;STRONG&gt;Environment Panel&lt;/STRONG&gt;&lt;SPAN&gt; found on the &lt;/SPAN&gt;&lt;SPAN&gt;right-hand edge&lt;/SPAN&gt;&lt;SPAN&gt; of the notebook, &lt;/SPAN&gt;&lt;SPAN&gt;select an &lt;/SPAN&gt;&lt;STRONG&gt;Accelerator&lt;/STRONG&gt;&lt;SPAN&gt; and the &lt;/SPAN&gt;&lt;STRONG&gt;AI Base environment&lt;/STRONG&gt;&lt;SPAN&gt; (this walkthrough uses &lt;/SPAN&gt;&lt;STRONG&gt;A10&lt;/STRONG&gt;&lt;SPAN&gt; on &lt;/SPAN&gt;&lt;STRONG&gt;AI v5&lt;/STRONG&gt;&lt;SPAN&gt;, as shown below)&lt;/SPAN&gt;&lt;SPAN&gt;. Finally, click &lt;/SPAN&gt;&lt;STRONG&gt;Apply&lt;/STRONG&gt;&lt;SPAN&gt; and then &lt;/SPAN&gt;&lt;STRONG&gt;Confirm&lt;/STRONG&gt;&lt;SPAN&gt;, as shown in the figure below.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="env_config_setup_v5.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/27687i4E18D75D08FA156E/image-size/large?v=v2&amp;amp;px=999" role="button" title="env_config_setup_v5.png" alt="env_config_setup_v5.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P class="lia-align-center"&gt;&lt;I&gt;&lt;SPAN&gt;Figure 2: Connecting to AI Runtime Serverless GPU cluster and configuring the Notebook Environment:&amp;nbsp;&lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt;Connect → Serverless GPU → Environment → &lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt;choose your &lt;/SPAN&gt;&lt;/I&gt;&lt;STRONG&gt;&lt;I&gt;Accelerator&lt;/I&gt;&lt;/STRONG&gt;&lt;I&gt;&lt;SPAN&gt; + the &lt;/SPAN&gt;&lt;/I&gt;&lt;STRONG&gt;&lt;I&gt;AI&lt;/I&gt;&lt;/STRONG&gt;&lt;I&gt;&lt;SPAN&gt; base environment&lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt; → Apply &amp;amp; Confirm.&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;Given that packages and dependencies are installed in the first notebook cell, there is no need to install within the cluster environment panel.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;Workflow overview&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;The notebook walks through six steps in order; each builds on the previous one.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-center" image-alt="mmt_2-1781055272547.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/27681i4B60E65E631DC9F3/image-size/large?v=v2&amp;amp;px=999" role="button" title="mmt_2-1781055272547.png" alt="mmt_2-1781055272547.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P class="lia-align-center"&gt;&lt;I&gt;&lt;SPAN&gt;Figure 3: An end-to-end workflow.&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 1: Setup — Environment and Unity Catalog&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;After attaching to Serverless GPU (see above: &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;Connect → Serverless GPU → choose your Accelerator + AI base environment → Apply and Confirm&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt;), the first steps are to install the required Python packages and configure your Unity Catalog project structure.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;On AI v5, the base environment already bundles&lt;/SPAN&gt; &lt;SPAN&gt;mlflow&amp;gt;=3&lt;/SPAN&gt;&lt;SPAN&gt; (skinny build), &lt;/SPAN&gt;&lt;SPAN&gt;nvidia-ml-py&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;threadpoolctl&lt;/SPAN&gt;&lt;SPAN&gt;, and &lt;/SPAN&gt;&lt;SPAN&gt;torch&lt;/SPAN&gt;&lt;SPAN&gt; — so the only package you install is &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Ultralytics&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;. &lt;/SPAN&gt;&lt;SPAN&gt;%pip&lt;/SPAN&gt;&lt;SPAN&gt; restarts Python automatically after the install. Then set a writable YOLO config directory to avoid permission issues. A &lt;/SPAN&gt;&lt;STRONG&gt;Package Verification&lt;/STRONG&gt;&lt;SPAN&gt; cell (in the notebook) confirms the expected packages are present and flags the uncommon case where Model Serving needs the full &lt;/SPAN&gt;&lt;SPAN&gt;mlflow&lt;/SPAN&gt;&lt;SPAN&gt; re-added on top of the skinny build.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;# ============================================================
# PACKAGE INSTALLATION — AI v5 (Serverless GPU, single GPU)
# ============================================================
# AI v5 pre-bundles mlflow&amp;gt;=3 (skinny), nvidia-ml-py, threadpoolctl, torch.
# Only ultralytics needs installing.
%pip install ultralytics==8.3.204 -q

# Note: %pip automatically restarts the Python environment after install.

# Set a writable YOLO config dir (avoids permission errors)
import os, uuid
config_dir = f'/tmp/yolo_config_{uuid.uuid4().hex[:8]}'
os.environ['YOLO_CONFIG_DIR'] = config_dir
os.makedirs(config_dir, exist_ok=True)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P&gt;&lt;SPAN&gt;Next, create or use a catalog, schema, and &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/connect/unity-catalog/volumes.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Unity Catalog Volume&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; for data, raw models, and model checkpoints from training runs. Use widgets for catalog, schema, volume, and model name so the same notebook can be reused across workspaces.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;# Widgets for catalog, schema, volume, model name
catalog_name = dbutils.widgets.get("catalog_name")   # e.g. "main"
schema_name  = dbutils.widgets.get("schema_name")    # e.g. "default"
volume_name  = dbutils.widgets.get("volume_name")    # e.g. "yolo_sgc"

spark.sql(f"CREATE SCHEMA IF NOT EXISTS `{catalog_name}`.`{schema_name}`")
spark.sql(f"CREATE VOLUME IF NOT EXISTS `{catalog_name}`.`{schema_name}`.`{volume_name}`")

project_location = f'/Volumes/{catalog_name}/{schema_name}/{volume_name}/'
os.makedirs(f'{project_location}runs/', exist_ok=True)
os.makedirs(f'{project_location}data/', exist_ok=True)
os.makedirs(f'{project_location}raw_model/', exist_ok=True)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 2: Data preparation&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;The dataset is configured via a YAML file (path, splits, class names). We download the COCO128 config and data to the volume, then split it into train (62.5%), validation (18.75%), and test (18.75%) with a fixed seed, updating the YAML with the new paths. For custom data, you typically adjust the YAML for your paths and classes. We use the Ultralytics &lt;/SPAN&gt;&lt;SPAN&gt;coco128.yaml&lt;/SPAN&gt;&lt;SPAN&gt;, downloaded to the UC Volume, but you can substitute your own config (e.g., &lt;/SPAN&gt;&lt;SPAN&gt;data.yaml&lt;/SPAN&gt;&lt;SPAN&gt;).&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;# Download COCO128 dataset configuration to UC Volume
import yaml

os.makedirs(f'{project_location}data/coco128', exist_ok=True)
config_url  = "https://github.com/ultralytics/ultralytics/raw/main/ultralytics/cfg/datasets/coco128.yaml"
config_path = f"{project_location}data/coco128.yaml"

download_file(config_url, config_path, "COCO128 config")

# Then load config, set data['path'] to volume path, download/extract dataset if needed, save updated YAML

Split the data and update the YAML with train/val/test image paths:
train_size, val_size, test_size = split_dataset(
    source_images_dir=f"{project_location}data/coco128/images/train2017",
    source_labels_dir=f"{project_location}data/coco128/labels/train2017",
    base_images_dir=f"{project_location}data/coco128/images",
    base_labels_dir=f"{project_location}data/coco128/labels",
    train_ratio=0.625,   # 62.5%
    val_ratio=0.1875,    # 18.75%
    random_seed=42,
)

# In the notebook: update data.yaml so 'train', 'val', 'test' point to the new split dirs
# (e.g. .../images/train, .../images/val, .../images/test)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;DIV style="border-left: 4px solid #d0d0d0; padding-left: 18px; margin: 16px 0;"&gt;
&lt;P style="margin: 0; font-size: 18px; line-height: 1.5;"&gt;&lt;EM&gt;&lt;FONT size="3" color="#808080"&gt;&lt;STRONG&gt;Important note:&lt;/STRONG&gt; COCO128 is used here only for demonstration. With ~128 images it is too small for production and will overfit. For real use cases, use larger datasets (e.g. 100K+ images or 1K+ domain-specific images). The same workflow applies — update data paths and config as needed.&lt;/FONT&gt;&lt;/EM&gt;&lt;/P&gt;
&lt;/DIV&gt;
&lt;H3&gt;&amp;nbsp;&lt;/H3&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 3: MLflow — Custom PyFunc Wrapper and Configuration&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;To deploy the trained YOLO model to &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/machine-learning/model-serving/index.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Model Serving&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;, we need a single, serializable API: the endpoint will receive requests (e.g., base64-encoded images) and return structured responses (e.g., bounding boxes). YOLO's native API expects file paths or NumPy arrays and returns a rich in-memory object, which is not what the serving layer expects.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The notebook therefore defines an &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#creating-custom-pyfunc-models" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;MLflow Custom PyFunc wrapper&lt;/SPAN&gt;&lt;/A&gt; &lt;SPAN&gt;YOLOWrapper(mlflow.pyfunc.PythonModel)&lt;/SPAN&gt;&lt;SPAN&gt; that accepts a DataFrame with an &lt;/SPAN&gt;&lt;SPAN&gt;image_base64&lt;/SPAN&gt;&lt;SPAN&gt; column and returns a DataFrame of detections (class, confidence, bbox columns).&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&lt;SPAN&gt;The wrapper class has three methods:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;load_context&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;loads the &lt;/SPAN&gt;&lt;SPAN&gt;.pt&lt;/SPAN&gt;&lt;SPAN&gt; artifact into &lt;/SPAN&gt;&lt;SPAN&gt;self.model&lt;/SPAN&gt;&lt;SPAN&gt; when the model is loaded (e.g. at serving startup).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;predict&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;accepts a DataFrame with &lt;/SPAN&gt;&lt;SPAN&gt;image_base64&lt;/SPAN&gt;&lt;SPAN&gt;, decodes each image, runs YOLO, and returns a DataFrame via &lt;/SPAN&gt;&lt;SPAN&gt;_format_predictions&lt;/SPAN&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;_format_predictions&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;converts YOLO's &lt;/SPAN&gt;&lt;SPAN&gt;Results&lt;/SPAN&gt;&lt;SPAN&gt; (&lt;/SPAN&gt;&lt;SPAN&gt;.boxes&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;.names&lt;/SPAN&gt;&lt;SPAN&gt;) into a single DataFrame with class name, class id, confidence, and bbox columns (&lt;/SPAN&gt;&lt;SPAN&gt;xyxy&lt;/SPAN&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;SPAN&gt;xywh&lt;/SPAN&gt;&lt;SPAN&gt;).&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&lt;SPAN&gt;We define the wrapper now so it's ready to use immediately after training completes in &lt;/SPAN&gt;&lt;STRONG&gt;Step 4&lt;/STRONG&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;class YOLOWrapper(mlflow.pyfunc.PythonModel):
    """Custom MLflow wrapper for YOLO models using base64-encoded images."""

    def load_context(self, context):
        """Load YOLO model from artifacts (called once when model is loaded)."""
        from ultralytics import YOLO
        model_path = context.artifacts["yolo_model"]
        self.model = YOLO(model_path, task='detect')

    def _format_predictions(self, predictions):
        """Convert YOLO Results to a single DataFrame with class, confidence, bbox columns."""
        import pandas as pd
        all_results = []
        for prediction in predictions:
            if prediction.boxes is not None:
                boxes = prediction.boxes
                for i in range(len(boxes)):
                    box_xyxy = boxes.xyxy[i].cpu().numpy()
                    box_xywh = boxes.xywh[i].cpu().numpy()
                    all_results.append({
                        "class_name": prediction.names[int(boxes.cls[i])],
                        "class_num": int(boxes.cls[i]),
                        "confidence": float(boxes.conf[i]),
                        "bbox_x1": float(box_xyxy[0]), "bbox_y1": float(box_xyxy[1]),
                        "bbox_x2": float(box_xyxy[2]), "bbox_y2": float(box_xyxy[3]),
                        "bbox_center_x": float(box_xywh[0]), "bbox_center_y": float(box_xywh[1]),
                        "bbox_width": float(box_xywh[2]), "bbox_height": float(box_xywh[3]),
                    })
        return pd.DataFrame(all_results)

    def predict(self, context, model_input):
        """Accept DataFrame with image_base64; decode, run YOLO, return DataFrame of detections."""
        import pandas as pd
        import base64
        from PIL import Image
        import io
        import numpy as np

        if 'image_base64' not in model_input.columns:
            raise ValueError("DataFrame must contain 'image_base64' column")
        all_predictions = []

        for image_base64 in model_input['image_base64'].tolist():
            image_bytes = base64.b64decode(image_base64)
            image_array = np.array(Image.open(io.BytesIO(image_bytes)))
            predictions = self.model.predict(image_array, verbose=False)
            all_predictions.extend(predictions)

        return self._format_predictions(all_predictions)&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;Step 3.1: MLflow configuration&lt;/STRONG&gt;&lt;/H4&gt;
&lt;P&gt;&lt;SPAN&gt;We &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/api_reference/_modules/mlflow/models/signature.html#infer_signature" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;infer the model signature&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; from a sample prediction using this custom wrapper (DataFrame with &lt;/SPAN&gt;&lt;SPAN&gt;image_base64&lt;/SPAN&gt;&lt;SPAN&gt; input and detection columns output). We also set the MLflow &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/api_reference/_modules/mlflow/entities/experiment_tag.html#ExperimentTag" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;experiment&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; (e.g., under &lt;/SPAN&gt;&lt;SPAN&gt;/Workspace/Shared/&lt;/SPAN&gt;&lt;SPAN&gt;) and enable system metrics logging, along with YOLO's MLflow integration and MLflow autologging.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;# Infer signature from a sample image (input: base64, output: bbox columns)
signature, input_example = infer_model_signature(model_path, sample_images[0])

# Enable system metrics and set experiment
experiment_name, experiment_id = setup_mlflow_experiment(
    use_workspaceUsers_path=False,
    expt_name_suffix="Experiments_YOLO_CoCo",
)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P&gt;&lt;SPAN&gt;The model is then registered to Unity Catalog (&lt;/SPAN&gt;&lt;SPAN&gt;mlflow.pyfunc.log_model&lt;/SPAN&gt;&lt;SPAN&gt;) using this wrapper and the best &lt;/SPAN&gt;&lt;SPAN&gt;checkpoint.pt&lt;/SPAN&gt;&lt;SPAN&gt; artifact (called after training in &lt;/SPAN&gt;&lt;STRONG&gt;Step 4:&lt;/STRONG&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;mlflow.pyfunc.log_model(
    name="model",
    python_model=YOLOWrapper(),
    artifacts={"yolo_model": model_path},
    signature=signature,
    input_example=input_example,
    registered_model_name=registered_model_name,
    pip_requirements=["ultralytics==...", "cloudpickle==...", "torch", "torchvision", "pillow", "numpy"],
)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 4: Model training&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;Train YOLO11n with your chosen hyperparameters (&lt;/SPAN&gt;&lt;SPAN&gt;epochs&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;batch size&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;learning rate&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;patience&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;dropout&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;weight decay&lt;/SPAN&gt;&lt;SPAN&gt;); these are specified in the &lt;/SPAN&gt;&lt;A href="https://docs.ultralytics.com/usage/cfg/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;config&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; variables within &lt;/SPAN&gt;&lt;SPAN&gt;model.train()&lt;/SPAN&gt;&lt;SPAN&gt; as shown in the code snippet. Training runs in a unique temp directory, and the results and validation metrics are copied into the volume under a named run folder (&lt;/SPAN&gt;&lt;SPAN&gt;{task}_{model}_{dataset}_{timestamp}_run_{run_id}&lt;/SPAN&gt;&lt;SPAN&gt;). The best &lt;/SPAN&gt;&lt;SPAN&gt;checkpoint&lt;/SPAN&gt;&lt;SPAN&gt; is saved and is then registered to Unity Catalog with the custom PyFunc wrapper (base64 in, structured detections out) defined in the previous step.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;model = YOLO(model_path)
results = model.train(
    task="detect",
    batch=4,
    device=0,                    # Single GPU for Serverless AI Runtime
    data=data_yaml_path,
    epochs=100,
    lr0=0.001,
    project=project_location,
    name=f"run_{timestamp}",
    patience=5,                  # Adjust as needed
    dropout=0.2,
    weight_decay=0.0005,
    save=True,
)
run_id = mlflow.last_active_run().info.run_id

# Register to Unity Catalog with custom PyFunc wrapper (base64 in, bbox out)
registered_model_name = register_yolo_model(
    run_id=run_id,
    model_path=best_model_path,
    catalog_name=catalog_name,
    schema_name=schema_name,
    model_name=model_name,
    signature=signature,
    input_example=input_example,
    data_yaml_path=data_yaml_path,
)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 5: Model evaluation&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;Evaluate the registered model on &lt;/SPAN&gt;&lt;SPAN&gt;validation&lt;/SPAN&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;SPAN&gt;test&lt;/SPAN&gt;&lt;SPAN&gt; sets (sample &lt;/SPAN&gt;&lt;SPAN&gt;predictions&lt;/SPAN&gt;&lt;SPAN&gt; and &lt;/SPAN&gt;&lt;SPAN&gt;metrics&lt;/SPAN&gt;&lt;SPAN&gt;), then run a &lt;/SPAN&gt;&lt;STRONG&gt;local serving test&lt;/STRONG&gt;&lt;SPAN&gt; by loading the &lt;/SPAN&gt;&lt;SPAN&gt;model&lt;/SPAN&gt;&lt;SPAN&gt; via &lt;/SPAN&gt;&lt;SPAN&gt;mlflow.pyfunc.load_model()&lt;/SPAN&gt;&lt;SPAN&gt; and calling it with &lt;/SPAN&gt;&lt;SPAN&gt;base64&lt;/SPAN&gt;&lt;SPAN&gt;-encoded images to confirm the same interface the endpoint will use.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;# Local serving test: same I/O as the deployed endpoint
model_uri = f"models:/{registered_model_name}/{latest_version}"
serving_model = mlflow.pyfunc.load_model(model_uri)

with open(test_image_path, 'rb') as f:
    image_base64 = base64.b64encode(f.read()).decode('utf-8')
input_df = pd.DataFrame({"image_base64": [image_base64]})
predictions = serving_model.predict(input_df)  # DataFrame with class_name, confidence, bbox_*
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H3&gt;&lt;STRONG&gt;Step 6: Model deployment&lt;/STRONG&gt;&lt;/H3&gt;
&lt;P&gt;&lt;SPAN&gt;After a manual checkpoint (e.g. a &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;"Proceed with Deployment"&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; widget), you can create or update a &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/aws/en/machine-learning/model-serving/custom-models" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Custom Model Serving&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; endpoint. The deployment configuration includes:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;A href="https://docs.databricks.com/en/dev-tools/sdk-python.html" target="_blank" rel="noopener"&gt;&lt;STRONG&gt;WorkspaceClient SDK&lt;/STRONG&gt;&lt;/A&gt;&lt;SPAN&gt; — enables programmatic endpoint management, ensuring deployments are repeatable, version-controlled, and integrated into automated workflows.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;&lt;A href="https://docs.databricks.com/aws/en/machine-learning/model-serving/create-manage-serving-endpoints#workload-types" target="_blank" rel="noopener"&gt;Small [endpoint workload compute size]&lt;/A&gt;&lt;/STRONG&gt;&lt;SPAN&gt;&amp;nbsp;and enabling scale-to-zero — minimizes compute costs during development and evaluation by provisioning resources on demand and releasing them when the endpoint is idle.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;A href="https://docs.databricks.com/en/ai-gateway/inference-tables/" target="_blank" rel="noopener"&gt;Unity AI Gateway inference tables&lt;/A&gt;&lt;SPAN&gt; — automatically logs all request and response payloads to a Unity Catalog Delta table, providing a built-in audit trail for monitoring, debugging, and downstream evaluation without additional instrumentation.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;Step 6.1: Create the endpoint with Unity AI Gateway enabled&lt;/STRONG&gt;&lt;/H4&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;from databricks.sdk import WorkspaceClient
from databricks.sdk.service.serving import (
    ServedEntityInput, EndpointCoreConfigInput,
    AiGatewayConfig, AiGatewayInferenceTableConfig,
)

w = WorkspaceClient()
w.serving_endpoints.create(
    name=endpoint_name,
    config=EndpointCoreConfigInput(
        served_entities=[
            ServedEntityInput(
                entity_name=registered_model_name,
                entity_version=str(model_version),
                workload_size="Small",
                scale_to_zero_enabled=True,
            )
        ]
    ),
    ai_gateway=AiGatewayConfig(
        inference_table_config=AiGatewayInferenceTableConfig(
            catalog_name=catalog_name,
            schema_name=schema_name,
            table_name_prefix=endpoint_name,
            enabled=True,
        )
    ),
)
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P&gt;&lt;SPAN&gt;Test the deployed endpoint by calling it with a &lt;/SPAN&gt;&lt;SPAN&gt;base64&lt;/SPAN&gt;&lt;SPAN&gt;-encoded image and verify the structured &lt;/SPAN&gt;&lt;SPAN&gt;bounding-box&lt;/SPAN&gt;&lt;SPAN&gt; response.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;H4&gt;&lt;STRONG&gt;Step 6.2: Call the endpoint with base64 input (same as local PyFunc test)&lt;/STRONG&gt;&lt;/H4&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;LI-CODE lang="python"&gt;import base64

with open(test_image_path, 'rb') as f:
    image_base64 = base64.b64encode(f.read()).decode('utf-8')

response = w.serving_endpoints.query(
    name=endpoint_name,
    dataframe_records=[{"image_base64": image_base64}],
)

# Response contains DataFrame with class_name, confidence, bbox_x1, bbox_y1, ...
&lt;/LI-CODE&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P&gt;&lt;SPAN&gt;Successful testing confirms the custom PyFunc wrapper's ability to handle base64-encoded image input and return a structured bounding-box output from the Model Serving endpoint, which are critical technical considerations detailed next.&lt;/SPAN&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;Key technical details&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;A few details are worth calling out for implementation and operations:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Base64 input:&lt;/STRONG&gt;&lt;SPAN&gt; The custom &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/python_api/mlflow.pyfunc.html#creating-custom-pyfunc-models" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;MLflow PyFunc&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; wrapper accepts a DataFrame with an &lt;/SPAN&gt;&lt;SPAN&gt;image_base64&lt;/SPAN&gt;&lt;SPAN&gt; column, where images are encoded as &lt;/SPAN&gt;&lt;SPAN&gt;base64&lt;/SPAN&gt;&lt;SPAN&gt; strings. &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;In our example, JPEG images are used; other formats (e.g. PNG, BMP) may work but have not been validated here.&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; Base64 encoding keeps the API simple and works across network boundaries for Model Serving.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Bounding box output:&lt;/STRONG&gt;&lt;SPAN&gt; The wrapper returns a DataFrame with columns such as &lt;/SPAN&gt;&lt;SPAN&gt;class_name&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;class_num&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;confidence&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;bbox_x1&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;bbox_y1&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;bbox_x2&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;bbox_y2&lt;/SPAN&gt;&lt;SPAN&gt;, and center/width/height. This structure is inferred once and used for the registered model's &lt;/SPAN&gt;&lt;A href="https://mlflow.org/docs/latest/ml/model/signatures/" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;signature&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Why we use a custom wrapper:&lt;/STRONG&gt;&lt;SPAN&gt; YOLO's native API expects image paths or NumPy arrays and returns a rich in-memory object; &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/machine-learning/model-serving/index.html" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;Model Serving&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; expects a single, serializable contract (DataFrame input and output) for HTTP requests and responses. The wrapper (1) accepts base64-encoded images in a DataFrame column (JSON-friendly), (2) loads the &lt;/SPAN&gt;&lt;SPAN&gt;.pt&lt;/SPAN&gt;&lt;SPAN&gt; artifact and runs the YOLO object detection task inside &lt;/SPAN&gt;&lt;SPAN&gt;predict&lt;/SPAN&gt;&lt;SPAN&gt;, and (3) returns a structured DataFrame of detections that the endpoint can serialize. Without it, the raw YOLO model could not be deployed as a standard PyFunc. The full implementation is in &lt;/SPAN&gt;&lt;STRONG&gt;Step 3&lt;/STRONG&gt;&lt;SPAN&gt; above.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Unity Catalog Volume structured layout:&lt;/STRONG&gt;&lt;SPAN&gt; Data is stored in &lt;/SPAN&gt;&lt;SPAN&gt;/Volumes/{catalog}/{schema}/{volume}/data/&lt;/SPAN&gt;&lt;SPAN&gt;. Pretrained weights are located in &lt;/SPAN&gt;&lt;SPAN&gt;raw_model/&lt;/SPAN&gt;&lt;SPAN&gt;. Each training run has its own dedicated folder under &lt;/SPAN&gt;&lt;SPAN&gt;runs/{task}_{model}_{dataset}_{timestamp}_run_{run_id}/&lt;/SPAN&gt;&lt;SPAN&gt;, which includes subfolders for &lt;/SPAN&gt;&lt;SPAN&gt;train/&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;validation_metrics/&lt;/SPAN&gt;&lt;SPAN&gt;, &lt;/SPAN&gt;&lt;SPAN&gt;validation_samples/&lt;/SPAN&gt;&lt;SPAN&gt;, and &lt;/SPAN&gt;&lt;SPAN&gt;test_samples/&lt;/SPAN&gt;&lt;SPAN&gt;.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Deployment safety:&lt;/STRONG&gt;&lt;SPAN&gt; A parameter widget (e.g. &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;"Proceed with Deployment"&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt;) gates the deployment cells so &lt;/SPAN&gt;&lt;I&gt;&lt;SPAN&gt;"Run All"&lt;/SPAN&gt;&lt;/I&gt;&lt;SPAN&gt; doesn't deploy by accident. Endpoint creation/update can take on the order of 10–20 minutes; the notebook can exit early and direct you to re-run or check the UI.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;SPAN&gt; &lt;A href="https://docs.databricks.com/aws/en/ai-gateway/overview-serving-endpoints" target="_blank" rel="noopener"&gt;Unity AI Gateway&lt;/A&gt;&lt;STRONG&gt;:&lt;/STRONG&gt; New endpoints are created with Unity AI Gateway inference table config (catalog, schema, table name prefix). The payload table is created and populated after the first requests; there can be a short delay before rows appear. You can query the table (e.g. &lt;/SPAN&gt;&lt;SPAN&gt;SELECT * FROM catalog.schema.endpoint_payload ORDER BY timestamp_ms DESC&lt;/SPAN&gt;&lt;SPAN&gt;) to inspect logged requests.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;Conclusion&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;The ability to train or fine-tune and deploy YOLO (You Only Look Once) models on Databricks Data Intelligence Platform provides enterprises with a high-performance, cost-optimized, and easily adoptable Computer Vision (CV) solution. Our walkthrough shows a complete path from raw images to a live YOLO endpoint on Databricks — no cluster provisioning, full MLflow tracking, Unity Catalog governance, and production-ready serving with built-in request logging. Swap COCO128 for your own dataset and the same workflow applies. As your data or model complexity grows, the same registration and deployment steps extend to multi-GPU and multi-node training patterns.&lt;/SPAN&gt;&lt;/P&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P class="lia-align-center"&gt;&lt;span class="lia-inline-image-display-wrapper lia-image-align-inline" image-alt="mmt_3-1781055272554.png" style="width: 999px;"&gt;&lt;img src="https://community.databricks.com/t5/image/serverpage/image-id/27683iFE126149736F5CEA/image-size/large?v=v2&amp;amp;px=999" role="button" title="mmt_3-1781055272554.png" alt="mmt_3-1781055272554.png" /&gt;&lt;/span&gt;&lt;/P&gt;
&lt;P class="lia-align-center"&gt;&lt;I&gt;&lt;SPAN&gt;Figure 4: Example validation of YOLO object detection inference on a sample of COCO128 images.&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV style="border-left: 4px solid #d0d0d0; padding-left: 18px; margin: 16px 0;"&gt;
&lt;P style="margin: 0; font-size: 18px; line-height: 1.5;"&gt;&lt;FONT color="#808080"&gt;&lt;EM&gt;&lt;FONT size="3"&gt;&lt;STRONG&gt;Single-GPU accelerator options:&lt;/STRONG&gt; This walkthrough uses a single A10 GPU, a cost-efficient choice for YOLO11n on small-to-medium datasets. The same notebook code also runs on a single H100 (Beta) for faster training — just select H100 as the Accelerator in the same AI v5 Environment panel; the rest of the workflow is unchanged. Check the &lt;A href="https://docs.databricks.com/release-notes/runtime/" target="_blank" rel="noopener"&gt;AI Runtime release notes&lt;/A&gt; for current accelerator availability and Beta status in your region.&lt;/FONT&gt;&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;H2&gt;&lt;STRONG&gt;Next steps&lt;/STRONG&gt;&lt;/H2&gt;
&lt;P&gt;&lt;SPAN&gt;Here's how you can try this out:&lt;/SPAN&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Single-node YOLO example:&lt;/STRONG&gt;&lt;SPAN&gt; Clone the &lt;/SPAN&gt;&lt;A href="https://github.com/databricks-industry-solutions/cv-playground" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;cv-playground&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; repository and run &lt;/SPAN&gt;&lt;A href="https://github.com/databricks-industry-solutions/cv-playground/blob/main/projects/ultralytics_databricks_examples/air-yolo11n-detect-coco128-singleGPU.ipynb" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;the notebook&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; in your Databricks workspace. &lt;/SPAN&gt;&lt;SPAN&gt;Attach it to an AI Runtime (Serverless GPU) with an AI base environment.&lt;/SPAN&gt;&lt;SPAN&gt; After running the cells, swap the COCO128 dataset for your own data and paths.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Larger-scale instance segmentation:&lt;/STRONG&gt;&lt;SPAN&gt; For a bigger example using YOLO, check out the &lt;/SPAN&gt;&lt;A href="https://github.com/databricks-industry-solutions/cv-playground/tree/main/projects/NuInsSeg" target="_blank" rel="noopener"&gt;&lt;SPAN&gt;NuInsSeg&lt;/SPAN&gt;&lt;/A&gt;&lt;SPAN&gt; project within the same repository.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Monitor and improve:&lt;/STRONG&gt;&lt;SPAN&gt; Use the &lt;/SPAN&gt;&lt;A href="https://docs.databricks.com/en/ai-gateway/inference-tables/" target="_blank" rel="noopener"&gt;Unity AI Gateway inference table&lt;/A&gt;&lt;SPAN&gt; to monitor model traffic, debug inputs and outputs, and feed insights back into your analytics or model improvement pipeline.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;H4&gt;&amp;nbsp;&lt;/H4&gt;
&lt;P class="lia-align-center"&gt;&lt;FONT size="3"&gt;&lt;STRONG&gt;&lt;I&gt;Stay tuned for the follow-up post on multi-GPU and multi-node YOLO model training on AI Runtime!&lt;/I&gt;&lt;/STRONG&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;HR /&gt;
&lt;P&gt;&lt;EM&gt;&lt;STRONG&gt;Acknowledgements:&lt;/STRONG&gt; Thanks to &lt;STRONG&gt;Lin Yuan&lt;/STRONG&gt; (Engineering, AI Runtime) for technical review and feedback.&lt;/EM&gt;&lt;/P&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;DIV style="border-left: 4px solid #d0d0d0; padding-left: 16px; margin: 16px 0;"&gt;
&lt;P style="margin: 0; font-size: 16px; line-height: 1.5;"&gt;&lt;FONT color="#808080"&gt;&lt;A id="ultralytics-licensing" target="_blank"&gt;&lt;/A&gt;&lt;FONT size="3"&gt;*&lt;/FONT&gt;&lt;EM&gt;&lt;FONT size="3"&gt;&lt;STRONG&gt;Note on licensing:&lt;/STRONG&gt; Ultralytics YOLO is dual-licensed: &lt;A href="https://www.ultralytics.com/license" target="_blank" rel="noopener"&gt;AGPL-3.0&lt;/A&gt; (default) or &lt;A href="https://www.ultralytics.com/license" target="_blank" rel="noopener"&gt;Enterprise&lt;/A&gt; for commercial use. Users should review &lt;A href="https://www.ultralytics.com/license" target="_blank" rel="noopener"&gt;https://www.ultralytics.com/license&lt;/A&gt; to determine which applies to their use case.&lt;/FONT&gt;&lt;/EM&gt;&lt;/FONT&gt;&lt;/P&gt;
&lt;/DIV&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;
&lt;P&gt;&lt;A href="#intro" target="_self"&gt;&lt;FONT size="2"&gt;&lt;EM&gt;^ Return to the top&lt;/EM&gt;&lt;/FONT&gt;&lt;/A&gt;&lt;/P&gt;</description>
    <pubDate>Fri, 12 Jun 2026 16:28:25 GMT</pubDate>
    <dc:creator>mmt</dc:creator>
    <dc:date>2026-06-12T16:28:25Z</dc:date>
    <item>
      <title>Train and Deploy YOLO Vision Model on Databricks AI Runtime (AIR)</title>
      <link>https://community.databricks.com/t5/technical-blog/train-and-deploy-yolo-vision-model-on-databricks-ai-runtime-air/ba-p/151558</link>
      <description>&lt;P&gt;&lt;I&gt;&lt;SPAN&gt;Train YOLO11n on &lt;A href="https://www.databricks.com/blog/introducing-ai-runtime-scalable-serverless-nvidia-gpus-databricks-training-and-finetuning"&gt;Databricks AI Runtime&lt;/A&gt;, register in Unity Catalog, and deploy to Model Serving with &lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt;base64&lt;/SPAN&gt;&lt;/I&gt;&lt;I&gt;&lt;SPAN&gt; encoded image input and Unity AI Gateway inference logging.&lt;/SPAN&gt;&lt;/I&gt;&lt;/P&gt;
&lt;UL&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;End-to-end workflow for Ultralytics &lt;/STRONG&gt;&lt;STRONG&gt;YOLO11n&lt;/STRONG&gt;&lt;STRONG&gt; Object Detection:&lt;/STRONG&gt;&lt;SPAN&gt; Training on single-node Databricks AI Runtime, utilizing MLflow tracking, and using Unity Catalog for artifacts and model registry.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Goal:&lt;/STRONG&gt;&lt;SPAN&gt; Provide a reproducible, production-ready path from GPU-trained &lt;/SPAN&gt;&lt;SPAN&gt;YOLO&lt;/SPAN&gt;&lt;SPAN&gt; to a Model Serving endpoint.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;LI style="font-weight: 400;" aria-level="1"&gt;&lt;STRONG&gt;Notebook Contents:&lt;/STRONG&gt;&lt;SPAN&gt; Covers environment setup, &lt;/SPAN&gt;&lt;SPAN&gt;COCO128&lt;/SPAN&gt;&lt;SPAN&gt; data preparation, MLflow autologging, custom &lt;/SPAN&gt;&lt;SPAN&gt;PyFunc&lt;/SPAN&gt;&lt;SPAN&gt; model registration (&lt;/SPAN&gt;&lt;SPAN&gt;base64&lt;/SPAN&gt;&lt;SPAN&gt; in, &lt;/SPAN&gt;&lt;SPAN&gt;bbox&lt;/SPAN&gt;&lt;SPAN&gt; out), evaluation, local serving validation, and deployment to a Model Serving endpoint with optional &lt;/SPAN&gt;&lt;SPAN&gt;request&lt;/SPAN&gt;&lt;SPAN&gt;/&lt;/SPAN&gt;&lt;SPAN&gt;response&lt;/SPAN&gt;&lt;SPAN&gt; logging via Unity AI Gateway inference tables.&lt;/SPAN&gt;&lt;/LI&gt;
&lt;/UL&gt;
&lt;P&gt;&amp;nbsp;&lt;/P&gt;</description>
      <pubDate>Fri, 12 Jun 2026 16:28:25 GMT</pubDate>
      <guid>https://community.databricks.com/t5/technical-blog/train-and-deploy-yolo-vision-model-on-databricks-ai-runtime-air/ba-p/151558</guid>
      <dc:creator>mmt</dc:creator>
      <dc:date>2026-06-12T16:28:25Z</dc:date>
    </item>
  </channel>
</rss>

