Repository navigation
Expand file tree
/
Copy pathDockerfile.py312
More file actions
143 lines (137 loc) · 8.73 KB
/
Copy pathDockerfile.py312
File metadata and controls
143 lines (137 loc) · 8.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
# The Python 3.12 image, for any model whose inference package needs a newer
# Python than the main image ships (see cluster/submit_job.py's
# resolve_k8s_image / a k8s profile's `image_overrides`). NOT a replacement
# for the main Dockerfile -- every model whose dependencies fit the main
# image's Python 3.11.10 + torch~=2.14 floor still runs from that image;
# route a model here only when it genuinely can't.
#
# Named after the Python version, not any one model, so the NEXT model that
# needs >=3.12 can potentially reuse this same image (if its dependency tree
# doesn't conflict with what's already installed below) instead of getting
# its own dedicated Dockerfile -- same axis this repo already uses for
# Dockerfile.v100 (GPU architecture, not model name). Renamed from
# Dockerfile.limix2 (2026-09-30) once a second Python-3.12-only model became
# plausible; LIMIX2 is still, as of this rename, the ONLY model actually
# built into this image -- the package-install section below (COPY/RUN pip
# install) is still LIMIX2-specific, not yet generalized, since there's only
# one real consumer to generalize FROM. If you're adding a second model here:
# check its dependencies don't conflict with LIMIX2's `torch>=2.9.1` pin (this
# image has no shared-floor protection the way the main image does -- see the
# `--no-deps`-free install below) before assuming it can share this image
# rather than needing its own.
#
# Why a separate-from-main image at all (LIMIX2's original reason, still the
# only concrete case): LIMIX2's inference package
# (github.com/limix-ldm-ai/LimiX) declares `requires-python = ">=3.12"` and
# `dependencies = ["torch>=2.9.1", ...]`. The main image is Python 3.11.10
# (inherited from its pytorch/pytorch:2.5.1-cuda12.4-cudnn9-runtime base) with
# a shared torch~=2.14 floor forced by Causilo (see pyproject.toml) -- a real,
# unconditional incompatibility (confirmed: no `pytorch/pytorch` tag pairs
# torch==2.9.1 with Python 3.12 -- pytorch/pytorch:2.9.1-cuda12.8-cudnn9-runtime
# still ships Python 3.11.14), not a workaround-able version-range overlap.
#
# Base: plain nvidia/cuda (Ubuntu 24.04 ships Python 3.12 natively, confirmed
# via `apt-get install python3.12`: Python 3.12.3), not pytorch/pytorch --
# torch itself comes from pip (the cu128 wheel bundles its own CUDA runtime
# libs, same as every other model's inference path in the main image; the
# node's NVIDIA driver + container toolkit supplies the rest, same as the main
# image's own "runtime"-not-"devel" base).
#
# Build and push (fill in your own registry -- keep this a DISTINCT tag from
# the main image's, e.g. `:py312`, never overwriting `:v1`):
# docker build --platform linux/amd64 -f Dockerfile.py312 -t <registry>/<you>/raman-bench:py312 .
# docker push <registry>/<you>/raman-bench:py312
# Then add `image_overrides: {"LIMIX2": "<registry>/<you>/raman-bench:py312"}`
# (plus any other model routed here) to your k8s profile (see
# cluster/profiles/k8s_example.yaml).
FROM nvidia/cuda:12.8.1-cudnn-runtime-ubuntu24.04
RUN apt-get update && apt-get install -y --no-install-recommends \
python3.12 \
python3.12-venv \
python3.12-dev \
python3-pip \
git \
build-essential \
&& rm -rf /var/lib/apt/lists/* \
&& ln -sf /usr/bin/python3.12 /usr/bin/python
# python3.12-venv: Ubuntu 24.04's system Python is "externally managed"
# (PEP 668) and refuses a bare `pip install` outside a venv/--break-system-packages;
# `--break-system-packages` below is fine here (this container runs nothing
# but this one pinned dependency set, unlike a dev machine's system Python).
# build-essential: same reasoning as the main Dockerfile -- torch's own triton
# JIT compilation path shells out to `cc` at call time.
# python3.12-dev: confirmed real crash without it -- triton's JIT-compiled CUDA
# utility shim (`cuda_utils.c`) `#include <Python.h>`, which build-essential's
# gcc alone doesn't provide (that only gives the compiler, not the interpreter's
# own C headers). Every LIMIX2 task failed identically until this was added:
# `fatal error: Python.h: No such file or directory`, raised during TabArena's
# mandatory warm-up step (require_warmup=True) -- fatal to the whole task even
# though the real fit code ran and produced a model afterward.
WORKDIR /app
# Install the released package WITHOUT the `[models]` extra (that extra pulls
# in causilo>=1.0.0, whose own unpinned `torch>=2.13` floor is exactly the
# conflict this dedicated image exists to avoid -- see the module-level note
# above). `[autogluon,benchmark]` covers everything LIMIX2Model
# itself needs (AbstractTorchModel lives in autogluon.tabular) plus
# run_experiment.py's own tabarena/tracking requirements, without dragging in
# every other model's third-party package (and torch constraint) along the
# way.
COPY pyproject.toml README.md requirements-limix2-git.txt ./
COPY src ./src
# --pre: same reasoning as the main Dockerfile (autogluon floor
# >=1.6.3b20260917, a prerelease).
#
# tabarena installed WITHOUT requirements-tabarena-git.txt's extras bracket
# (tabicl,ebm,search_spaces,realmlp,tabdpt,tabm,perpetualboosting,chimeraboost,
# nori) -- confirmed as a real build failure: the `nori` extra pulls
# `synthefy-nori` -> `synthefy` -> `pyvinecopulib`, which needs Eigen3 headers
# at build time (`CMake Error ... Could not find ... Eigen3`) that this image
# doesn't carry. None of those nine extras' models run in this image (it's
# LIMIX2-only), so the bare package -- same git commit pin as
# requirements-tabarena-git.txt, kept in sync by hand -- is all that's needed;
# `tabarena.models.limix_2` itself has no extra-gated dependency.
# Split into separate RUN layers (same reasoning as the main Dockerfile's own split,
# 2026-10-01): a single layer bundling torch+autogluon+tabarena+LimiX grew to several
# GB in one blob, which a registry push repeatedly stalled on indefinitely through this
# network's path. Smaller per-step layers push independently.
RUN pip install --no-cache-dir --break-system-packages --pre -e ".[autogluon,benchmark]"
# Bumped 2026-10-01: was still pinned to 3db69f9 (the commit current when this Dockerfile was
# written, 2026-09-15), two bumps behind requirements-tabarena-git.txt's actual current pin
# (9d771c3) despite this comment's own "kept in sync by hand" claim -- confirmed stale, not assumed;
# fixed when actually activating LIMIX2 for the first real cluster run. Keep this in sync with
# requirements-tabarena-git.txt's pin going forward -- there is no automated check for drift between
# the two files. Bumped with it 2026-10-09 to 742133b4 (9d771c3 + LightPFN/PrismBoost cherry-picks) and
# 2026-10-13 to 66198aba (+ many-class support for LightPFN and TabFM+).
RUN pip install --no-cache-dir --break-system-packages --pre \
"tabarena @ git+https://github.com/mario-koddenbrock/tabarena.git@66198abac051459bdcb8e5106836b910a6a64ad4#subdirectory=packages/tabarena"
# requirements-limix2-git.txt installed WITHOUT --no-deps here, unlike the
# main image's documented install path (see that file's own comment): the
# --no-deps workaround exists only because the main image's shared
# torch~=2.14 floor (from causilo, skipped above) would otherwise get
# clobbered by LimiX's torch>=2.9.1 dependency. This image has no such floor
# to protect -- LimiX-2 is the only model running in it -- so its dependency
# tree (including its own torch>=2.9.1 pin) installs normally, letting pip's
# resolver pick a consistent version across LimiX + autogluon + tabarena
# instead of hand-pinning one.
RUN pip install --no-cache-dir --break-system-packages --pre -r requirements-limix2-git.txt
# nvtx: the one extra LimiX needs that isn't in its own declared dependency
# tree (see requirements-limix2-git.txt's own comment) -- still required even
# without --no-deps above.
RUN pip install --no-cache-dir --break-system-packages nvtx
# tabpfn-extensions: LimiX2Model routes >10-class targets through
# tabarena.utils.wrapper_utils.import_many_class_classifier (ManyClassClassifier),
# which lives in the `[models]` extra skipped above -- confirmed live: every
# cancer_cell_cooh/nh2 and rruff_mineral_raw LIMIX2 task failed with
# `ModuleNotFoundError: No module named 'tabpfn_extensions'`. torch pinned to the
# version already installed so tabpfn's own dependency tree can't move LimiX's
# torch; setuptools<80 for the same pkg_resources reason as pyproject.toml.
RUN pip install --no-cache-dir --break-system-packages --pre \
"tabpfn-extensions>=0.4.3" "setuptools<80" \
"torch==$(python -c 'import torch; print(torch.__version__.split("+")[0])')"
# scripts/ and cluster/ are what run_experiment.py and k8s_entrypoint.sh need
# at runtime -- same reasoning as the main Dockerfile.
COPY scripts ./scripts
COPY cluster ./cluster
COPY configs ./configs
RUN chmod +x cluster/k8s_entrypoint.sh
ENTRYPOINT ["/bin/bash", "cluster/k8s_entrypoint.sh"]