You shard, the platform counts
The platform doesn’t split datasets. You build the shards on your machine, zip them, and upload them to jobs/<name>/shards/ in your bucket.
Each worker unpacks its zip flat into its data root. Zip the contents, never the folder that holds them:
# right: the worker sees data_root/images/ and data_root/data.yaml
zip -r shard_0.zip images/ data.yaml
# wrong: the worker sees data_root/shard/images/ and your paths break
zip -r shard_0.zip shard/Upload from the Files page, the upload panel in step 6 of the training wizard, or rclone copy ./shards resontech:<bucket>/jobs/<name>/shards. The SDK uploads them for you.
Splitting
Every example job splits with round-robin striding in build_shards_hf.py. Edit HF_DATASET, NUM_SHARDS and MAX_EXAMPLES at the top of that file.
indices = list(range(len(train_ds)))
partitions = [indices[i::NUM_SHARDS] for i in range(NUM_SHARDS)]Shard size sets influence
The FL server averages the workers’ weights by the sample count each one reports:
global = Σ (samples_i × weights_i) ÷ Σ samples_ireturn {"weights": model.get_weights(), "samples": len(train_ds)} # alwaysThresholds for every data type
Layouts by data type
“Measured” rows come from real runs; the rest are starting points to check on your data.
Image classification
job_classify, job_medical, job_imagenet_scratch. Class names come from folder names.
images/train/<class_name>/00000000.jpg
images/val/<class_name>/00000000.jpg # the full validation set, in every shard
data.yaml # nc: 101, names: [...]Object detection
job_yolo11, job_csgo. The shard’s data.yaml is an Ultralytics descriptor; its path is rewritten to the data root at runtime.
images/train/*.jpg labels/train/*.txt # cx cy w h, normalized
images/val/*.jpg labels/val/*.txt
data.yaml # nc, names, train:, val:Text and LLM fine-tuning
job_llm, job_agent, job_lm_scratch. Only the LoRA adapter travels each round, so traffic stays flat at any base size.
data.jsonl # {"instruction": ..., "input": ..., "output": ...}
# job_agent, job_lm_scratch: {"text": "..."} per line- Budget by tokens, not rows. A row can be 100 tokens or 8,000. Equalize token mass, or return token counts as
samples. - Keep each dialogue or reasoning trace in one shard. Group by conversation id, then stride.
- Deduplicate before sharding. Near-duplicates spread over shards act as a hidden upweight.
- Sort by length, then stride, so every shard gets the same mix of short and long rows.
Speech recognition
job_speech (Whisper-small + LoRA). Paths in data.jsonl are relative to the shard root.
audio/00000000.wav # 16 kHz mono PCM_16
data.jsonl # {"audio": "audio/00000000.wav", "text": "..."}Other example jobs
Before you upload
- N zips for N workers, lowercase .zip.
- Contents zipped flat, with no wrapper folder.
- Every shard opens and loads with the job’s own loader on your machine.
- Every label present in every shard, or the stratified splitter used.
- The same validation set in every shard, with no overlap with training.
- Each shard fits the worker disk; batch and method fit its VRAM.
- Your
fl_train_modelreturns a truesamples.