Paths and environment variables inside the container
The directories, manifest.json, environment variables and experiment.json the platform puts into a training container.
The GEO_* environment variables and /geo/… paths are exactly the names the platform actually provides.
Directories
/geodataset/GEO_DATA_DIR — original dataset files, read-only. All in place before training startsmanifest.jsonfile list · kinds · metadataimages/one subdirectory per kind (image)annotations/(annotation)timeseries/(timeseries)tabular/(tabular)pointclouds/(pointcloud)work/GEO_WORK_DIR — writable workspace. Disappears when the run endsexperiment.jsonGEO_CONFIG — snapshot of the experiment settings (advanced)| Path | Environment variable | Contents |
|---|---|---|
/geo/dataset | GEO_DATA_DIR | Original dataset files (read-only). Several runs reuse the same cache, so do not write here |
/geo/work | GEO_WORK_DIR | Checkpoints · converted labels · intermediate outputs. Disappears with the pod |
/geo/experiment.json | GEO_CONFIG | Full snapshot of the settings. Read it only when the environment variables are not enough |
manifest.json
It sits directly under GEO_DATA_DIR. path is relative to GEO_DATA_DIR, so join the two as is to open a file.
{
"dataset": { "id": "ds-…", "name": "…" },
"files": [
{ "path": "images/site_008.jpg", "kind": "image",
"meta": { "width": 640, "height": 480, "format": "JPEG",
"label_files": [{ "filename": "site_008.json", "format": "labelme" }] } },
{ "path": "annotations/site_008.json", "kind": "annotation",
"meta": { "format": "labelme", "annotation_count": 2, "match_rate": 1.0 } },
{ "path": "tabular/features.csv", "kind": "tabular",
"meta": { "row_count": 300, "columns": [{ "name": "label", "dtype": "object" }] } }
]
}
kindis one ofimage·annotation·timeseries·tabular·pointcloud, and matches the subdirectory the file is placed in. Only files that passed validation are placed.- The directory also holds a hidden file the platform uses for its cache check (
.stamp). Read the file list frommanifest.jsoninstead of scanning the directory. - The folder structure inside a zip is flattened on upload. If names collide,
-2is appended to the later one. Do not rely on structure such as per-class subfolders. metaholds values filled in by the platform validators (image size and paired label files, annotation format, row count and columns of a table, and so on). The example is shortened and may omit keys.- Labels arrive in a different shape for each kind. Image data gets annotation files (COCO JSON · LabelMe JSON · VOC XML),
tabulargets a column inside the CSV, and point clouds get an integer property inside the PLY file. timeseriesandtabularuse the same.csv/.parquetfiles. The modality chosen when the dataset was created tells them apart. Themetaoftabularhas notime_columnkey at all.- The trainer does the train/val split. The platform does not split the files; it only writes the ratio and seed into
splitinexperiment.json.
Environment variables
| Variable | Contents |
|---|---|
GEO_DATA_DIR | Dataset directory — /geo/dataset |
GEO_WORK_DIR | Workspace — /geo/work |
GEO_CONFIG | Experiment settings file — /geo/experiment.json |
GEO_PARAM_EXPERIMENT_ID | Training run ID (experiment_id in experiment.json) |
GEO_PARAM_EXPERIMENT_NAME | Experiment name (= MLflow experiment name) |
GEO_PARAM_TASK | Task (for example object_detection) |
GEO_PARAM_FRAMEWORK | Framework chosen in wizard step 2 (for example yolo) |
GEO_PARAM_MODEL | Model variant (for example yolo26n) |
GEO_PARAM_DATASET_ID | Dataset ID |
GEO_PARAM_DEVICE | 0 or cpu. Inside the pod, GPUs are always numbered from 0 |
GEO_HP_<name> | Hyperparameters chosen in the wizard (for example GEO_HP_EPOCHS=50, GEO_HP_LR=0.001) |
GEO_RUNTIME_IMAGE | Address of the image that runs this training. It may be pinned to a digest |
CUDA_VISIBLE_DEVICES | 0 when one or more GPUs are assigned, empty otherwise. Even with several slots, only GPU 0 is visible |
MLFLOW_TRACKING_URI | The platform's MLflow address |
MLFLOW_TRACKING_TOKEN | A token issued for each run and revoked when it ends. The MLflow client reads it by itself. Not set on deployments with MLflow authentication turned off |
MLFLOW_EXPERIMENT_NAME | Name of the experiment the platform created in advance — use this value as is |
MLFLOW_RUN_ID | The run the platform created in advance. mlflow.start_run() attaches to this run |
GEO_HP_*naming rule: hyperparameter keys must match^[a-z][a-z0-9_]*$, and the environment variable name is that key converted to upper case as is (lr→GEO_HP_LR). Nested structures and lists cannot be expressed as environment variables, so they appear only inexperiment.json.- All values are strings. Convert them to the type of the default value when you read them (see the
hyperparameter()function in the example). Booleans arrive as lower-casetrue/false. In Pythonbool("false")is true, so compare the string directly. - Only keys present in the step 7 YAML of the wizard arrive. At submission the keys are checked against the allow list of the chosen framework, so a key the catalog does not have cannot be sent. If the YAML is submitted empty, no
GEO_HP_*arrives at all, so keep a default in the image for every value. - What is not passed in: object storage addresses and keys. The platform fetches the data in advance, so no storage credentials reach the training container.
- The platform does not set
PYTHONUNBUFFERED. To see logs in real time, addENV PYTHONUNBUFFERED=1to your Dockerfile.
Resource limits
| Item | Default | When exceeded |
|---|---|---|
| Memory | Training container limit of 64Gi (server setting GEO_MLOPS_TRAINING_RUNTIME_MEMORY_LIMIT). /dev/shm counts toward it | The pod ends with exit code 137 and the training fails |
/dev/shm | 2Gi (server setting GEO_MLOPS_TRAINING_RUNTIME_SHM_SIZE) | With many DataLoader workers or large batches it can run short. Ask the operator to raise it |
| GPU | The number of slots chosen in wizard step 10. 0 means CPU | For a GPU-only framework, 0 is rejected at submission |
experiment.json (advanced)
All the main values also come as environment variables, so most images do not read this file. Read it only when you need the classes list, the split ratio or nested hyperparameters. The file contains no credentials, so it is safe to write it to the log.
{
"experiment_id": "7abfb12e3a8d…",
"name": "mnist-external-smoke-3",
"tenant": "DEMO",
"created_at": "2026-09-21T06:59:47Z",
"task": "object_detection",
"framework": "yolo",
"model": "yolo26n",
"classes": ["head", "helmet"],
"split": { "method": "random", "train_percent": 80, "seed": 0 },
"hyperparameters": { "epochs": 2 },
"device": "cpu",
"gpu": 0,
"evaluation": { "benchmark": true, "speed_test": false },
"export": { "onnx": false, "tensorrt": false },
"serving": { "runtime": "cpu" },
"register": { "enabled": false, "model_name": "" },
"pretrained": { "source": "catalog" },
"dataset": { "id": "ds-…", "name": "…", "file_count": 16,
"path": "/geo/dataset", "manifest": "/geo/dataset/manifest.json",
"pointcloud_labels": null },
"paths": { "data_dir": "/geo/dataset", "work_dir": "/geo/work" },
"mlflow": { "experiment_name": "mnist-external-smoke-3", "run_id": "…" }
}
| Group | Meaning |
|---|---|
experiment_id · name · tenant · created_at | Which run this is. name = MLflow experiment name |
task · framework · model · classes | What is being trained. classes contains only the classes chosen for this experiment |
split | Split instructions. The trainer does the split itself |
hyperparameters | The parsed object with the same values as GEO_HP_* |
device · gpu | Compute resources |
evaluation · export · serving | Requests for after training. If you do not support them, ignore them |
register | Whether to register, and the model name. The platform does the registration itself |
pretrained | Where the starting weights come from — Pretrained weights |
dataset · paths · mlflow | Locations and the run, for reference. dataset.pointcloud_labels tells which PLY property is the class and which is the instance ID (null without point clouds) |