# Getting Started with Modal ## Basic Structure Every Modal script follows this pattern: ```python import modal # 1. Create an app app = modal.App("my-training-app") # 2. Define the container image image = modal.Image.debian_slim(python_version="3.11").pip_install( "torch", "einops", "numpy", ) # 3. Define a GPU function @app.function(gpu="A100", image=image, timeout=3600) def train(): import torch device = torch.device("cuda") print(f"Using GPU: {torch.cuda.get_device_name(0)}") # Your training code here return results # 4. Local entrypoint @app.local_entrypoint() def main(): results = train.remote() print(results) ``` ## Running Scripts ```bash # Set up Modal token (if not already done) modal token set --token-id --token-secret # Run the script modal run train_modal.py # Run in background modal run --detach train_modal.py ``` ## Key Concepts | Concept | Description | |---------|-------------| | `App` | Container for your Modal functions | | `Image` | Container image with dependencies | | `@app.function` | Decorator to mark functions for remote execution | | `@app.local_entrypoint` | Entry point that runs locally | | `.remote()` | Call a function remotely on Modal infrastructure | ## Image Building Install dependencies at image build time, not runtime: ```python # CORRECT - install in image image = modal.Image.debian_slim(python_version="3.11").pip_install( "torch", "einops", ) # WRONG - install at runtime (slow, unreliable) @app.function(...) def train(): import subprocess subprocess.run(["pip", "install", "torch"]) # Don't do this ``` ## Print Statements Print statements in remote functions appear in Modal logs in real-time: ```python @app.function(gpu="A100", image=image, timeout=3600) def train(): print("Starting training...") # Appears in logs for step in range(100): if step % 10 == 0: print(f"Step {step}") # Progress updates return {"done": True} ```