- Posted on
- • Artificial Intelligence
Artificial Intelligence Python Packaging
- Author
-
-
- User
- linuxbash
- Posts by this author
- Posts by this author
-
Artificial Intelligence Python Packaging on Linux: Ship Models Without the Headaches
If you’ve ever spent an afternoon watching pip compile NumPy or PyTorch from source, you know the pain: hours lost, cryptic compiler errors, and an end user who just wants your model to run. Good news—you can avoid most of that. With the right packaging approach, AI apps install cleanly, upgrade predictably, and deploy anywhere your Linux shells go.
This guide explains why AI packaging is tricky, then gives you a practical path: isolate environments, prefer binary wheels, pin for reproducibility, and package your own tools the way pros do. Everything is Linux-first, Bash-friendly, and comes with apt, dnf, and zypper commands.
Why AI packaging is different (and what that means for you)
Native code everywhere: NumPy, SciPy, PyTorch, TensorFlow and friends ship C/C++/Fortran/CUDA code. Building them from source needs compilers, headers, and time—you don’t want this on your users’ machines.
Platform compatibility: Wheels are tagged for specific platforms (manylinux, musllinux) and Python ABIs. Pick the wrong wheel and you’re back to source builds.
GPU stacks: CUDA/ROCm compatibility is sensitive to driver and runtime versions. PyTorch often ships CUDA-enabled wheels; TensorFlow expects you to install CUDA/cuDNN separately on Linux.
Reproducibility and security: Unpinned deps and mutable package indexes turn today’s working environment into tomorrow’s mystery. Hash-pinning and constraints files help a lot.
The upshot: Prefer prebuilt binary wheels, manage isolated environments, and lock your dependencies.
0) System prep (compilers, Python, headers)
Even if you’re avoiding source builds, some tooling needs common dev packages. Install these once on your machine or builder.
Debian/Ubuntu (apt):
sudo apt update
sudo apt install -y \
python3 python3-venv python3-pip python3-dev \
build-essential gcc g++ make pkg-config \
git cmake
Fedora/RHEL (dnf):
sudo dnf -y groupinstall "Development Tools"
sudo dnf -y install \
python3 python3-pip python3-devel \
git cmake pkgconfig
openSUSE (zypper):
sudo zypper refresh
sudo zypper install -y \
python3 python3-pip python3-devel \
git gcc gcc-c++ make cmake pkg-config
Note:
On Debian/Ubuntu you need
python3-venvto usepython -m venv.If you plan GPU work, install NVIDIA drivers and CUDA per vendor docs; don’t mix system CUDA with wheels unless the package supports it.
1) Use isolated environments (no sudo pip; no system pollution)
Create a per-project virtual environment so you can freely install and remove AI stacks.
mkdir -p ~/code/ai-demo
cd ~/code/ai-demo
python3 -m venv .venv
. .venv/bin/activate
python -m pip install --upgrade pip
Confirm isolation:
which python
python -c "import sys; print(sys.prefix)"
Why it matters:
Keeps system Python clean.
Reproducible across machines/CI.
Lets you test CPU vs GPU stacks side-by-side.
2) Prefer binary wheels and match platform/GPU
Install prebuilt wheels to avoid compiling. Use dedicated indexes when frameworks provide CPU/GPU-specific wheels.
Fast, CPU-only installs:
# Force binaries where possible
pip install --only-binary=:all: numpy scipy
# TensorFlow CPU (ensure Python and glibc versions are supported)
pip install --only-binary=:all: tensorflow
PyTorch examples:
# CPU wheels
pip install --index-url https://download.pytorch.org/whl/cpu torch torchvision torchaudio
# CUDA 12.1 wheels (large download)
pip install --index-url https://download.pytorch.org/whl/cu121 torch torchvision torchaudio
Tips:
Manylinux vs musllinux: Alpine Linux uses musl, not glibc. Prefer musllinux wheels on Alpine or use a glibc-based image.
pip install --only-binary=:all:helps avoid source builds. If a package has no wheel for your platform, remove the flag and expect compilers to kick in.Read framework compatibility matrices (CUDA/ROCm, Python versions) to avoid runtime mismatch errors.
3) Pin, lock, and verify (reproducible installs)
Use constraints or lock files to keep environments stable across machines. Hash-pinning adds supply-chain safety.
Quick-start with pip-tools:
pip install pip-tools
# requirements.in is human-edited
cat > requirements.in <<'EOF'
numpy>=1.26
# Lock PyTorch to a minor release train on Linux
torch==2.3.* ; platform_system == "Linux"
EOF
# Compile a fully-resolved, hash-pinned requirements.txt
pip-compile --generate-hashes -o requirements.txt requirements.in
# Install exactly what was compiled
pip-sync requirements.txt
Or use plain pip with hashes:
pip install --require-hashes -r requirements.txt
Extra hardening:
Use a private index or an allowlist proxy.
Avoid
--trusted-hostunless necessary.Record
pip freeze > requirements.lockfor debugging diffs.
4) Package your own AI tool the right way (pyproject.toml + wheels)
Package your code so others can pip install it—CLI and all. Keep large model files out of your wheel; download them at first run or make them optional extras.
Create a minimal project:
mkdir -p ai_pkg/src/ai_pkg
cd ai_pkg
cat > src/ai_pkg/__init__.py <<'EOF'
__version__ = "0.1.0"
EOF
cat > src/ai_pkg/cli.py <<'EOF'
def main():
import numpy as np
try:
import torch
x = torch.tensor([1.0, 2.0, 3.0])
print("mean (torch):", x.mean().item())
except Exception as e:
a = np.array([1.0, 2.0, 3.0])
print("mean (numpy fallback):", a.mean(), f"(torch unavailable: {e})")
EOF
Declare modern packaging metadata (PEP 517/518/621) in pyproject.toml:
cat > pyproject.toml <<'EOF'
[build-system]
requires = ["hatchling>=1.24.2"]
build-backend = "hatchling.build"
[project]
name = "ai-pkg-example"
version = "0.1.0"
description = "Tiny packaged AI demo with CPU fallback"
readme = "README.md"
requires-python = ">=3.9"
license = {text = "MIT"}
authors = [{name = "Your Name"}]
dependencies = [
"numpy>=1.26",
# Torch on Linux x86_64; skip on aarch64 or non-Linux to avoid broken installs
"torch>=2.3 ; platform_system == 'Linux' and platform_machine == 'x86_64'",
]
[project.optional-dependencies]
# Let users opt into GPU-specific deps via: pip install ai-pkg-example[gpu]
gpu = [
"torch==2.3.* ; platform_system == 'Linux' and platform_machine == 'x86_64'"
]
[project.scripts]
ai-demo = "ai_pkg.cli:main"
EOF
Add a simple README.md:
echo "# ai-pkg-example" > README.md
Build a wheel and sdist:
# Install build tooling
pip install build
# Build distributions
python -m build
# Your files appear in ./dist/
ls -1 dist
Optional: publish via TestPyPI first.
Install pipx for isolated tooling:
apt:
sudo apt update
sudo apt install -y pipx
pipx ensurepath
dnf:
sudo dnf install -y pipx
pipx ensurepath
zypper:
sudo zypper install -y pipx
pipx ensurepath
Then:
pipx install twine
twine check dist/*
twine upload --repository-url https://test.pypi.org/legacy/ dist/*
Test installation from TestPyPI:
python -m venv /tmp/testenv && . /tmp/testenv/bin/activate
pip install -i https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple ai-pkg-example
ai-demo
Notes:
Put large models on a CDN or Hugging Face and download at first run, caching under
~/.cache/yourapp.If you need native extensions, produce manylinux wheels using the official manylinux containers and
auditwheel. Alpine users should target musllinux.
5) Keep installs small, fast, and secure
Minimize heavy deps: do you need the full
torchor just ONNX Runtime ortflite-runtime?Optional extras: GPU packages as
[gpu]extras avoid bloating CPU-only installs.Lazy imports: import heavy frameworks only when needed to speed CLI startup.
Scan for known vulns:
pipx install pip-audit pip-audit -r requirements.txtVerify integrity with hash-pinning and immutable artifact storage (e.g., internal PyPI mirror).
Real-world patterns that work
CLI microtools: Package a small pre/post-processing tool with
console_scripts. Userspip install yourtooland runyourtoolfrom Bash.Server deploys: Build a wheel in CI, publish to an internal index, and
pip install yourpkg==X.Y.Z --only-binary=:all:in Docker images.CPU/GPU split: Publish a base package
mlapp(CPU) plusmlapp[gpu]extras or a siblingmlapp-gputhat declares the right CUDA wheel index.
Common pitfalls (and how to avoid them)
Using
sudo pip: this corrupts system Python and fights with your package manager. Always usevenvor containers.Alpine + manylinux wheels: glibc vs musl mismatch. Use musllinux wheels or a glibc base image.
TensorFlow GPU on Linux: the pip wheel expects system CUDA/cuDNN. Install the exact versions from TensorFlow’s compatibility table.
Mixing CUDA versions: PyTorch CUDA 12.1 wheels expect matching drivers. Read the install page and choose the correct
--index-url.
Conclusion and next steps
Packaging is as critical to AI success as your model’s accuracy. On Linux, a disciplined approach—isolated environments, binary wheels, locked dependencies, and a clean pyproject.toml—turns “it works on my machine” into “it works everywhere.”
Try this now:
1) Create a new venv and install NumPy or PyTorch with binary wheels.
2) Lock your environment with pip-compile and hashes.
3) Package a tiny CLI with pyproject.toml and publish to TestPyPI.
Have questions about your specific stack (CUDA, Alpine, CI/CD, private indexes)? Bring your Bash logs and we’ll help you make it bulletproof.