{ "cells": [ { "cell_type": "markdown", "id": "intro", "metadata": {}, "source": [ "# Building and Running a Model Locally with Podman\n", "\n", "Before deploying a model to the Datamint server, it's worth running it as a real container on your\n", "own machine first, a \"local deploy\". It's the same image format and the same `/invocations`\n", "serving contract the server uses, just built and run entirely on your machine with `podman`. If it\n", "builds and predicts correctly here, you've already caught most of what would go wrong on a real\n", "deployment.\n", "\n", "`01_deploy_registered_model.ipynb` covers the next step: taking a model you've validated locally\n", "and actually deploying it on the Datamint server.\n", "\n", "> **IMPORTANT:** This notebook requires `podman` to be installed **and running** on your machine,\n", "> the Python `podman` package alone is not enough, it just talks to the podman API socket.\n", ">\n", "> ```bash\n", "> # rootless (typical for local dev)\n", "> systemctl --user enable --now podman.socket\n", "> ```\n", ">" ] }, { "cell_type": "markdown", "id": "setup-header", "metadata": {}, "source": [ "## Setup" ] }, { "cell_type": "code", "execution_count": null, "id": "setup", "metadata": {}, "outputs": [], "source": [ "import datamint.mlflow as datamint_mlflow\n", "from datamint import Api\n", "\n", "PROJECT_NAME = 'Segmentation_Tutorial'\n", "MODEL_NAME = 'Segmentation_Tutorial_Model'\n", "\n", "api = Api()\n", "datamint_mlflow.set_project(PROJECT_NAME)" ] }, { "cell_type": "markdown", "id": "pick-header", "metadata": {}, "source": [ "## 1. Pick a Model Version and a Resource\n" ] }, { "cell_type": "code", "execution_count": null, "id": "pick", "metadata": {}, "outputs": [], "source": [ "model_uri = f'models:/{MODEL_NAME}/latest'\n", "\n", "resources = list(api.resources.get_list(project_name=PROJECT_NAME, limit=1))\n", "resource = resources[0]\n", "\n", "print('Model URI:', model_uri)\n", "print('Resource :', resource.filename, resource.id)" ] }, { "cell_type": "markdown", "id": "build-header", "metadata": {}, "source": [ "## 2. Build the Podman Image\n", "\n", "`build_docker_image` downloads the model, generates a serving `Dockerfile`, and runs `podman build`, all locally. Build output streams to stdout as it happens, pass `log_callback` if you'd rather\n", "capture it yourself (e.g. into a file).\n", "\n", "`with_gpu=False` here since this is a CPU-only walkthrough." ] }, { "cell_type": "code", "execution_count": null, "id": "build", "metadata": {}, "outputs": [], "source": [ "from datamint.mlflow.models.docker_build import (\n", " build_docker_image,\n", " remove_docker_image,\n", " run_docker_container,\n", " stop_docker_container,\n", ")\n", "\n", "built = build_docker_image(model_uri, with_gpu=False)\n", "print(built)" ] }, { "cell_type": "markdown", "id": "run-header", "metadata": {}, "source": [ "## 3. Run the Container\n", "\n", "Starts the image with `podman run`, publishing the model server's port to the host. By default\n", "`run_docker_container` polls the container's `/ping` endpoint until it responds (or raises if it\n", "crashes/times out first), so by the time this cell returns the container is ready for requests." ] }, { "cell_type": "code", "execution_count": null, "id": "run", "metadata": {}, "outputs": [], "source": [ "running = run_docker_container(built.image_name, built.image_tag)\n", "print(running)" ] }, { "cell_type": "markdown", "id": "predict-header", "metadata": {}, "source": [ "## 4. Predict Against the Running Container\n", "\n", "`predict_local` posts directly to the container's `/invocations` endpoint. Pass `resource_id` + `api_client` to run on a resource\n", "already in Datamint (as below), or `file_path` for a local file instead." ] }, { "cell_type": "code", "execution_count": null, "id": "predict", "metadata": {}, "outputs": [], "source": [ "from datamint.mlflow.models.local_inference import predict_local\n", "\n", "annotations = predict_local(\n", " container_port=running.host_port,\n", " resource_id=resource.id,\n", " api_client=api,\n", ")\n", "\n", "print(f'Annotations: {len(annotations)}')\n", "for ann in annotations:\n", " print(' ', ann)" ] }, { "cell_type": "markdown", "id": "cleanup-header", "metadata": {}, "source": [ "## 5. Clean Up\n", "\n", "These containers/images are meant to be disposable dev artifacts, not left running. `stop_docker_container`\n", "stops (and by default removes) the container; `remove_docker_image` drops the built image too." ] }, { "cell_type": "code", "execution_count": null, "id": "cleanup", "metadata": {}, "outputs": [], "source": [ "stop_docker_container(running)\n", "remove_docker_image(built.image_name, built.image_tag)" ] }, { "cell_type": "markdown", "id": "summary", "metadata": {}, "source": [ "## Summary\n", "\n", "This notebook covered:\n", "- Building a podman image for a registered model entirely on your own machine\n", "- Running that image locally and waiting for it to become ready\n", "- Predicting against it, with results parsed into `Annotation` objects\n", "- Tearing the container and image back down when you're done\n", "\n", "Model behaving as expected here means it's ready for the next step: deploying it for real on the\n", "Datamint server, covered in `01_deploy_registered_model.ipynb`." ] } ], "metadata": { "kernelspec": { "display_name": "env", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.12.3" } }, "nbformat": 4, "nbformat_minor": 5 }