diff --git a/.github/workflows/cleanup-ghcr.yml b/.github/workflows/cleanup-ghcr.yml new file mode 100644 index 000000000..a13d8e7af --- /dev/null +++ b/.github/workflows/cleanup-ghcr.yml @@ -0,0 +1,68 @@ +name: "Prune old GHCR images" + +on: + schedule: + - cron: '0 2 * * *' # daily at 02:00 UTC + push: + branches: [ docker ] + registry_package: + types: [ published ] + +permissions: + contents: read + packages: write + +jobs: + prune: + runs-on: ubuntu-latest + + steps: + - name: Install dependencies + run: | + sudo apt-get update + sudo apt-get install -y jq + curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg \ + | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg + echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" \ + | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null + sudo apt-get update + sudo apt-get install -y gh + + - name: Delete all but the newest version for CPU & GPU images + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + OWNER: ${{ github.repository_owner }} + run: | + set -euo pipefail + + for IMAGE in deep-learning-crash-course deep-learning-crash-course-gpu; do + echo + echo "πŸ” Processing package: $OWNER/$IMAGE" + versions=$(gh api --paginate \ + -H "Accept: application/vnd.github.v3+json" \ + /orgs/$OWNER/packages/container/$IMAGE/versions) + + # pick most recent by creation date + newest_id=$(echo "$versions" \ + | jq -r 'sort_by(.created_at) | reverse | .[0].id') + echo "πŸ›‘ Keeping version $newest_id for $IMAGE" + + # delete every version except the newest + echo "$versions" | jq -c '.[]' | while read version; do + id=$(echo "$version" | jq -r '.id') + if [[ "$id" != "$newest_id" ]]; then + echo "β†’ Deleting version $id of $IMAGE" + for attempt in 1 2 3; do + if gh api -X DELETE \ + -H "Accept: application/vnd.github.v3+json" \ + /orgs/$OWNER/packages/container/$IMAGE/versions/$id; then + echo " βœ… Deleted $id" + break + else + echo " ⚠️ Attempt $attempt failed, retrying in $((5*attempt))s…" + sleep $((5*attempt)) + fi + done + fi + done + done \ No newline at end of file diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml new file mode 100644 index 000000000..603ce70c8 --- /dev/null +++ b/.github/workflows/docker-publish.yml @@ -0,0 +1,58 @@ +name: Build & Publish DLCC Images + +on: + push: + branches: [ docker ] + paths: + - 'docker/Dockerfile' + - 'docker/Dockerfile.gpu' + - 'docker/requirements.txt' + - 'docker/docker-compose.yml' + - '.github/workflows/docker-publish.yml' + pull_request: + branches: [ docker ] + paths: + - 'docker/Dockerfile' + - 'docker/Dockerfile.gpu' + - 'docker/requirements.txt' + - 'docker/docker-compose.yml' + - '.github/workflows/docker-publish.yml' + +env: + REGISTRY: ghcr.io + IMAGE_NAME: deep-learning-crash-course + +jobs: + build-and-push: + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + strategy: + matrix: + variant: [cpu, gpu] + + steps: + - uses: actions/checkout@v4 + + - name: Setup QEMU & Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to GHCR + uses: docker/login-action@v3 + with: + registry: ${{ env.REGISTRY }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - name: Build & push ${{ matrix.variant }} image + uses: docker/build-push-action@v3 + with: + context: ./docker + file: ./docker/Dockerfile${{ matrix.variant == 'gpu' && '.gpu' || '' }} + platforms: linux/amd64${{ matrix.variant == 'cpu' && ',linux/arm64' || '' }} + push: ${{ github.event_name == 'push' }} + tags: | + ${{ env.REGISTRY }}/deeptrackai/${{ env.IMAGE_NAME }}${{ matrix.variant == 'gpu' && '-gpu' || '' }}:latest + ${{ env.REGISTRY }}/deeptrackai/${{ env.IMAGE_NAME }}${{ matrix.variant == 'gpu' && '-gpu' || '' }}:${{ github.sha }} \ No newline at end of file diff --git a/docker/.vscode/settings.json b/docker/.vscode/settings.json new file mode 100644 index 000000000..275214867 --- /dev/null +++ b/docker/.vscode/settings.json @@ -0,0 +1,10 @@ +{ + // Allow the VS Code widget renderer to fetch JS directly + "jupyter.widgetScriptSources": [ + "localhost:8888", + "jsdelivr.com", + "unpkg.com" + ], + // Make sure VS Code always uses the container’s Python + "python.defaultInterpreterPath": "/opt/conda/bin/python" +} diff --git a/docker/Dockerfile b/docker/Dockerfile new file mode 100644 index 000000000..5cb75638d --- /dev/null +++ b/docker/Dockerfile @@ -0,0 +1,37 @@ +# --------------------------------------------------------------------------------- +# Universal multi-arch image (works on both Apple Silicon & Intel) +# --------------------------------------------------------------------------------- +FROM quay.io/jupyter/datascience-notebook:python-3.11 +# ---------- system utilities ------------------------------------------------------ +USER root +RUN apt-get update && \ + apt-get install -y --no-install-recommends git && \ + rm -rf /var/lib/apt/lists/* +USER ${NB_UID} + +# ---------- copy the course ------------------------------------------------------- +WORKDIR /home/jovyan/work +RUN git clone --depth 1 https://github.com/DeepTrackAI/DeepLearningCrashCourse.git . + +# ---------- ensure correct ownership --------------------------------------------- +USER root +RUN chown -R ${NB_UID}:${NB_GID} /home/jovyan/work +USER ${NB_UID} + +# ---------- extra Python deps ----------------------------------------------------- +# CPU-only PyTorch (wheels from CPU index) +RUN pip install --no-cache-dir \ + torch==2.7.0 torchvision==0.22.0\ + --index-url https://download.pytorch.org/whl/cpu + +# CPU-only PyG (and its C/C++ extensions) +RUN pip install --no-cache-dir \ + torch-geometric \ + -f https://data.pyg.org/whl/torch-2.7.0+cpu.html + +# Then install your extra deps +COPY ./requirements.txt /tmp/ +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +EXPOSE 8888 +CMD ["start-notebook.sh"] \ No newline at end of file diff --git a/docker/Dockerfile.gpu b/docker/Dockerfile.gpu new file mode 100644 index 000000000..0c08699b3 --- /dev/null +++ b/docker/Dockerfile.gpu @@ -0,0 +1,33 @@ +# ──────────────────────────────────────────────────────────────────────────────── +# GPU-enabled Jupyter + PyTorch + your course +# ──────────────────────────────────────────────────────────────────────────────── +FROM quay.io/jupyter/pytorch-notebook:cuda12-python-3.11.9 +# ---------- system utilities ------------------------------------------------------ +USER root +RUN apt-get update && \ + apt-get install -y --no-install-recommends git && \ + rm -rf /var/lib/apt/lists/* +USER ${NB_UID} + +# ---------- copy the course ------------------------------------------------------- +WORKDIR /home/jovyan/work +RUN git clone --depth 1 https://github.com/DeepTrackAI/DeepLearningCrashCourse.git . + +# ---------- ensure correct ownership --------------------------------------------- +USER root +RUN chown -R ${NB_UID}:${NB_GID} /home/jovyan/work +USER ${NB_UID} + +# ---------- extra Python deps ----------------------------------------------------- +# Base image already has CUDA-enabled PyTorch 2.7+ +# Install PyG CUDA wheels matching torch 2.7.0+cu121 +RUN pip install --no-cache-dir \ + torch-geometric \ + -f https://data.pyg.org/whl/torch-2.7.0+cu121.html + +# Then install your extra deps +COPY ./requirements.txt /tmp/ +RUN pip install --no-cache-dir -r /tmp/requirements.txt + +EXPOSE 8888 +CMD ["start-notebook.sh"] diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 000000000..c44d8b7ab --- /dev/null +++ b/docker/README.md @@ -0,0 +1,74 @@ +# Deep Learning Crash Course + +[![Early Access - Use Code PREORDER for 25% Off](https://img.shields.io/badge/Early%20Access%20Now%20Available-Use%20Code%20PREORDER%20for%2025%25%20Off-orange)](https://nostarch.com/deep-learning-crash-course) +by Benjamin Midtvedt, JesΓΊs Pineda, Henrik Klein Moberg, Harshith Bachimanchi, Joana B. Pereira, Carlo Manzo, Giovanni Volpe +No Starch Press, San Francisco (CA), 2025 +ISBN-13: 9781718503922 +[https://nostarch.com/deep-learning-crash-course](https://nostarch.com/deep-learning-crash-course) + +--- + +# Deep Learning Crash Course Docker Image + +![Docker Image CI](https://github.com/DeepTrackAI/DeepLearningCrashCourse/actions/workflows/docker-publish.yml/badge.svg) + +A ready-to-run JupyterLab environment with all notebooks and dependencies baked in. +Works on Intel & Apple-Silicon Macs, Linux Γ—86_64 & ARM64; also provides an NVIDIA-CUDA-enabled variant for GPU hosts. + +--- + +## Prerequisites + +- **Docker** + - macOS / Windows β†’ [Docker Desktop](https://www.docker.com/products/docker-desktop) + - Linux β†’ Docker Engine + (optional) [NVIDIA Container Toolkit](https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/) +- (Optional) **VS Code** + [Dev Containers extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-containers) + +--- + +## Quick Start + +### 1. Pull the image + +**CPU-only (multi-arch)** +```bash +docker pull ghcr.io/deeptrackai/deep-learning-crash-course:latest +``` + +**GPU-enabled (amd64 + CUDA)** +```bash +docker pull ghcr.io/deeptrackai/deep-learning-crash-course-gpu:latest +``` + +### 2. Start JupyterLab + +**CPU-only (multi-arch)** +```bash +docker run --rm -it \ + -p 8888:8888 \ + ghcr.io/deeptrackai/deep-learning-crash-course:latest +``` + +**GPU-enabled (amd64 + CUDA)** +```bash +docker run --rm -it --gpus all \ + -p 8888:8888 \ + ghcr.io/deeptrackai/deep-learning-crash-course-gpu:latest +``` +### 3. Run in JupyterLab ... + +After startup, copy the URL with token (e.g., http://127.0.0.1:8888/lab?token=…) into your browser to access JupyterLab. + +### ... or attach in VS Code (Dev Containers) + + 1. In VS Code, open Command Palette (`Ctrl+Shift+P`). + + 2. Run **Dev Containers: Attach to Running Container...** + + 3. Select your **CPU** or **GPU** container from the list. A new VS Code window will pop up. + + 4. Install Python & Jupyter extensions when prompted. + + 5. **Open Folder** β†’ `/home/jovyan/work` and **Select Kernel** β†’ `/opt/conda/bin/python` (Python 3.11). + + 6. Open any `.ipynb` and run cells. If `ipywidgets` fails, Reload window. \ No newline at end of file diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 000000000..82145c046 --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,9 @@ +services: + dlcc: + build: . + ports: + - "8888:8888" + volumes: + - ../:/home/jovyan/work # bind-mount whole repo β‡’ edits persist + environment: + - JUPYTER_ENABLE_LAB=yes diff --git a/docker/requirements.txt b/docker/requirements.txt new file mode 100644 index 000000000..cf6af41d4 --- /dev/null +++ b/docker/requirements.txt @@ -0,0 +1,25 @@ +deeptrack==2.0.1 +deeplay==0.1.3 +pytorch-lightning==2.5.1 +numpy==2.2.5 +matplotlib==3.10.3 +IPython==9.2.0 +Pillow==11.2.1 +contractions==0.1.73 +datasets==3.6.0 +huggingface_hub==0.31.4 +kornia==0.8.1 +networkx==3.4.2 +opencv-python==4.11.0.86 +pandas==2.2.3 +scipy==1.15.3 +seaborn==0.13.2 +scikit-image==0.25.2 +scikit-learn==1.6.1 +spacy==3.8.6 +tifffile==2025.5.10 +torchmetrics==1.6.1 +tqdm==4.67.1 +transformers==4.51.3 +warmup_scheduler==0.3 +pygame==2.6.1 \ No newline at end of file