You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This tutorial walks through exporting a Gemma4 model with mobius, building ORT + GenAI from source, and serving the model through Foundry Local's OpenAI-compatible API.
Tested on: 8x NVIDIA H200 GPUs, CUDA 13.0, Ubuntu, Python 3.12
Prerequisites
Linux machine with NVIDIA GPU
conda (or any Python 3.10+ environment)
~20 GB disk space for model weights
Step 1: Environment Setup
# Create conda environment
conda create -n onnx python=3.12 -y
conda activate onnx
# Verify CUDA
nvidia-smi # Should show GPU info
nvcc --version # Need CUDA toolkit (12.8+ or 13.0)
If CUDA toolkit is not installed:
# CUDA 13.0 (if available)# Or download from https://developer.nvidia.com/cuda-downloadsexport CUDA_HOME=/usr/local/cuda-13.0 # adjust to your installationexport PATH=$CUDA_HOME/bin:$PATH
Set up cuDNN (if not system-installed):
# cuDNN is often available via pip
pip install nvidia-cudnn-cu12
# Create a cuDNN home directory for ORT build
mkdir -p ~/cudnn9/{lib,include}
CUDNN_PKG=$(python -c "import nvidia.cudnn; import pathlib; print(pathlib.Path(nvidia.cudnn.__file__).parent)")
ln -sf $CUDNN_PKG/lib/*~/cudnn9/lib/
ln -sf $CUDNN_PKG/include/*~/cudnn9/include/
export CUDNN_HOME=~/cudnn9
Step 2: Build ORT from Source
ORT 1.27+ is required for Gemma4 support (head_dim=512 in GroupQueryAttention).
Note: The build may fail on test runner targets (onnxruntime_perf_test) due to abseil linking.
The core library and pybind module still build. Build the wheel manually:
cd build/Linux/Release
python ~/dev/onnxruntime/setup.py bdist_wheel
pip install dist/onnxruntime-*.whl --force-reinstall --no-deps
Verify:
importonnxruntimeasortprint(ort.__version__) # 1.27.0print(ort.get_available_providers()) # Should include CUDAExecutionProvider
Step 3: Create ORT Install Layout for GenAI
GenAI needs headers + libraries in a specific layout:
importonnxruntime_genaiasogmodel=og.Model("~/gemma4-e2b-it-onnx")
tokenizer=og.Tokenizer(model)
prompt="<bos><start_of_turn>user\nWhat is the capital of France?<end_of_turn>\n<start_of_turn>model\n"ids=tokenizer.encode(prompt)
params=og.GeneratorParams(model)
params.set_search_options(max_length=80, do_sample=False, repetition_penalty=1.2)
gen=og.Generator(model, params)
gen.append_tokens(ids)
whilenotgen.is_done():
gen.generate_next_token()
output=gen.get_sequence(0)
print(tokenizer.decode(output))
# Expected: "The capital of France is Paris."# Speed: ~12-15 tok/s on CPU
Step 6: Install Foundry Local
pip install foundry-local-sdk
# IMPORTANT: Foundry installs its own onnxruntime + onnxruntime-genai.# Re-install our builds to override:
pip install ~/dev/onnxruntime/build/Linux/Release/dist/onnxruntime-*.whl --force-reinstall --no-deps
pip install ~/dev/onnxruntime-genai/build/Linux/Release/wheel/onnxruntime_genai_cuda-*.whl --force-reinstall --no-deps
Why this works: Foundry's native core creates symlinks from its binary directory to the Python-installed ORT/GenAI packages. When we install our versions, Foundry automatically picks them up.
Fix .so.dbg bug (if present):
# Foundry may ship a .so.dbg file that confuses the file finder
CORE_DIR=$(python -c "import foundry_local_core; import pathlib; print(pathlib.Path(foundry_local_core.__file__).parent / bin)")
rm -f "$CORE_DIR/Microsoft.AI.Foundry.Local.Core.so.dbg"
CACHE_DIR="/tmp/foundry-cache"# or ~/.foundry/cache on default installs
MODEL_DIR="$CACHE_DIR/Custom/gemma-4-e2b-it"
mkdir -p "$MODEL_DIR"# Copy all exported model files
cp -r ~/gemma4-e2b-it-onnx/*"$MODEL_DIR/"
Create inference_model.json in the model directory:
Safetensors external data has 16-byte alignment — insufficient for cuBLAS FP16 GEMM. Always use --external-data onnx which provides 4096-byte alignment.
Foundry SDK .so.dbg bug: get_native_binary_paths() may resolve to .so.dbg instead of .so. Remove the .dbg file as workaround.
GenAI provider name: genai_config.json should use "cuda" (lowercase) not "CUDAExecutionProvider" for the provider key. The NormalizeProviderName() function in GenAI doesn't normalize CUDA.
Foundry SDK model_cache_dir: The Python SDK's get_model() works for custom models in the Custom/ directory, but list_models() may not show them in the full catalog listing.
Running Gemma4 on Foundry Local — Complete Guide
This tutorial walks through exporting a Gemma4 model with mobius, building ORT + GenAI from source, and serving the model through Foundry Local's OpenAI-compatible API.
Tested on: 8x NVIDIA H200 GPUs, CUDA 13.0, Ubuntu, Python 3.12
Prerequisites
Step 1: Environment Setup
If CUDA toolkit is not installed:
Set up cuDNN (if not system-installed):
Step 2: Build ORT from Source
ORT 1.27+ is required for Gemma4 support (head_dim=512 in GroupQueryAttention).
Verify:
Step 3: Create ORT Install Layout for GenAI
GenAI needs headers + libraries in a specific layout:
Step 4: Build GenAI from Source
GenAI 0.14+ (with PR #2103) is required for Gemma4 multimodal support.
Verify (should show NO API version warnings):
Step 5: Export Gemma4 with mobius
This produces:
Quick test (without Foundry):
Step 6: Install Foundry Local
Fix
.so.dbgbug (if present):Step 7: Register Custom Model in Foundry Local
Find the cache directory and place your model:
Create
inference_model.jsonin the model directory:{ "Name": "gemma-4-e2b-it", "PromptTemplate": { "user": "<start_of_turn>user\n{Content}<end_of_turn>", "assistant": "<start_of_turn>model\n{Content}<end_of_turn>", "prompt": "<start_of_turn>user\n{Content}<end_of_turn>\n<start_of_turn>model" } }Step 8: Serve and Test
Using OpenAI Python client:
Expected Results
m.load()succeedsKnown Issues
CUDA EP segfault during GenAI prefill (issue CUDA EP: CUBLAS misaligned address crash during prefill with Gemma4 model microsoft/onnxruntime-genai#2120). Use CPU EP for now (set
provider_options: []in genai_config.json).Safetensors external data has 16-byte alignment — insufficient for cuBLAS FP16 GEMM. Always use
--external-data onnxwhich provides 4096-byte alignment.Foundry SDK
.so.dbgbug:get_native_binary_paths()may resolve to.so.dbginstead of.so. Remove the.dbgfile as workaround.GenAI provider name:
genai_config.jsonshould use"cuda"(lowercase) not"CUDAExecutionProvider"for the provider key. TheNormalizeProviderName()function in GenAI doesn't normalize CUDA.Foundry SDK
model_cache_dir: The Python SDK'sget_model()works for custom models in theCustom/directory, butlist_models()may not show them in the full catalog listing.Versions Used