Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Distributed training orchestration across clusters. Scales PyTorch/TensorFlow/HuggingFace from laptop to 1000s of nodes. Built-in hyperparameter tuning with Ray Tune, fault tolerance, elastic scaling. Use when training massive models across multiple machines or running distributed hyperparameter sweeps.
.claude/skills/openlair-ray-train/SKILL.md| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-10 | ✗→✓ | ▲ Improved | 53% | 0% |
| case-16 | ✗→✓ | ▲ Improved | 332% | 0% |
| case-01 | ✓→✓ | = Same ✓ | 172% | 0% |
| case-02 | ✓→✓ | = Same ✓ | 107% | 0% |
| case-03 | ✓→✓ | = Same ✓ | 160% | 0% |
Ray Train scales machine learning training from single GPU to multi-node clusters with minimal code changes.
Installation:
bashpip install -U "ray[train]"
Basic PyTorch training (single node):
pythonimport ray from ray import train from ray.train import ScalingConfig from ray.train.torch import TorchTrainer import torch import torch.nn as nn # Define training function def train_func(config): # Your normal PyTorch code model = nn.Linear(10, 1) optimizer = torch.optim.SGD(model.parameters(), lr=0.01) # Prepare for distributed (Ray handles device placement) model = train.torch.prepare_model(model) for epoch in range(10): # Your training loop output = model(torch.randn(32, 10)) loss = output.sum() loss.backward() optimizer.step() optimizer.zero_grad() # Report metrics (logged automatically) train.report({"loss": loss.item(), "epoch": epoch}) # Run distributed training trainer = TorchTrainer( train_func, scaling_config=ScalingConfig( num_workers=4, # 4 GPUs/workers use_gpu=True ) ) result = trainer.fit() print(f"Final loss: {result.metrics['loss']}")
That's it! Ray handles:
Original single-GPU code:
pythonmodel = MyModel().cuda() optimizer = torch.optim.Adam(model.parameters()) for epoch in range(epochs): for batch in dataloader: loss = model(batch) loss.backward() optimizer.step()
Ray Train version (scales to multi-GPU/multi-node):
pythonfrom ray.train.torch import TorchTrainer from ray import train def train_func(config): model = MyModel() optimizer = torch.optim.Adam(model.parameters()) # Prepare for distributed (automatic device placement) model = train.torch.prepare_model(model) dataloader = train.torch.prepare_data_loader(dataloader) for epoch in range(epochs): for batch in dataloader: loss = model(batch) loss.backward() optimizer.step() # Report metrics train.report({"loss": loss.item()}) # Scale to 8 GPUs trainer = TorchTrainer( train_func, scaling_config=ScalingConfig(num_workers=8, use_gpu=True) ) trainer.fit()
Benefits: Same code runs on 1 GPU or 1000 GPUs
pythonfrom ray.train.huggingface import TransformersTrainer from transformers import AutoModelForCausalLM, AutoTokenizer, TrainingArguments def train_func(config): # Load model and tokenizer model = AutoModelForCausalLM.from_pretrained("gpt2") tokenizer = AutoTokenizer.from_pretrained("gpt2") # Training arguments (HuggingFace API) training_args = TrainingArguments( output_dir="./output", num_train_epochs=3, per_device_train_batch_size=8, learning_rate=2e-5, ) # Ray automatically handles distributed training from transformers import Trainer trainer = Trainer( model=model, args=training_args, train_dataset=train_dataset, ) trainer.train() # Scale to multi-node (2 nodes × 8 GPUs = 16 workers) trainer = TransformersTrainer( train_func, scaling_config=ScalingConfig( num_workers=16, use_gpu=True, resources_per_worker={"GPU": 1} ) ) result = trainer.fit()
pythonfrom ray import tune from ray.train.torch import TorchTrainer from ray.tune.schedulers import ASHAScheduler def train_func(config): # Use hyperparameters from config lr = config["lr"] batch_size = config["batch_size"] model = MyModel() optimizer = torch.optim.Adam(model.parameters(), lr=lr) model = train.torch.prepare_model(model) for epoch in range(10): # Training loop loss = train_epoch(model, optimizer, batch_size) train.report({"loss": loss, "epoch": epoch}) # Define search space param_space = { "lr": tune.loguniform(1e-5, 1e-2), "batch_size": tune.choice([16, 32, 64, 128]) } # Run 20 trials with early stopping tuner = tune.Tuner( TorchTrainer( train_func, scaling_config=ScalingConfig(num_workers=4, use_gpu=True) ), param_space=param_space, tune_config=tune.TuneConfig( num_samples=20, scheduler=ASHAScheduler(metric="loss", mode="min") ) ) results = tuner.fit() best = results.get_best_result(metric="loss", mode="min") print(f"Best hyperparameters: {best.config}")
Result: Distributed hyperparameter search across cluster
pythonfrom ray import train from ray.train import Checkpoint def train_func(config): model = MyModel() optimizer = torch.optim.Adam(model.parameters()) # Try to resume from checkpoint checkpoint = train.get_checkpoint() if checkpoint: with checkpoint.as_directory() as checkpoint_dir: state = torch.load(f"{checkpoint_dir}/model.pt") model.load_state_dict(state["model"]) optimizer.load_state_dict(state["optimizer"]) start_epoch = state["epoch"] else: start_epoch = 0 model = train.torch.prepare_model(model) for epoch in range(start_epoch, 100): loss = train_epoch(model, optimizer) # Save checkpoint every 10 epochs if epoch % 10 == 0: checkpoint = Checkpoint.from_directory( train.get_context().get_trial_dir() ) torch.save({ "model": model.state_dict(), "optimizer": optimizer.state_dict(), "epoch": epoch }, checkpoint.path / "model.pt") train.report({"loss": loss}, checkpoint=checkpoint) trainer = TorchTrainer( train_func, scaling_config=ScalingConfig(num_workers=8, use_gpu=True) ) # Automatically resumes from checkpoint if training fails result = trainer.fit()
pythonfrom ray.train import ScalingConfig # Connect to Ray cluster ray.init(address="auto") # Or ray.init("ray://head-node:10001") # Train across 4 nodes × 8 GPUs = 32 workers trainer = TorchTrainer( train_func, scaling_config=ScalingConfig( num_workers=32, use_gpu=True, resources_per_worker={"GPU": 1, "CPU": 4}, placement_strategy="SPREAD" # Spread across nodes ) ) result = trainer.fit()
Launch Ray cluster:
bash# On head node ray start --head --port=6379 # On worker nodes ray start --address=<head-node-ip>:6379
Use Ray Train when:
Key advantages:
Use alternatives instead:
Issue: Ray cluster not connecting
Check ray status:
bashray status # Should show: # - Nodes: 4 # - GPUs: 32 # - Workers: Ready
If not connected:
bash# Restart head node ray stop ray start --head --port=6379 --dashboard-host=0.0.0.0 # Restart worker nodes ray stop ray start --address=<head-ip>:6379
Issue: Out of memory
Reduce workers or use gradient accumulation:
pythonscaling_config=ScalingConfig( num_workers=4, # Reduce from 8 use_gpu=True ) # In train_func, accumulate gradients for i, batch in enumerate(dataloader): loss = model(batch) / accumulation_steps loss.backward() if (i + 1) % accumulation_steps == 0: optimizer.step() optimizer.zero_grad()
Issue: Slow training
Check if data loading is bottleneck:
pythonimport time def train_func(config): for epoch in range(epochs): start = time.time() for batch in dataloader: data_time = time.time() - start # Train... start = time.time() print(f"Data loading: {data_time:.3f}s")
If data loading is slow, increase workers:
pythondataloader = DataLoader(dataset, num_workers=8)
Multi-node setup: See references/multi-node.md for Ray cluster deployment on AWS, GCP, Kubernetes, and SLURM.
Hyperparameter tuning: See references/hyperparameter-tuning.md for Ray Tune integration, search algorithms (Optuna, HyperOpt), and population-based training.
Custom training loops: See references/custom-loops.md for advanced Ray Train usage, custom backends, and integration with other frameworks.
Supported accelerators:
| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-01 | pass→pass | 8,304 | 6,462 | -22% | 1 | 1 | 0% | 1,417 | 3,855 | +172% | 0 | 0 | — |
case-02 | pass→pass | 13,009 | 11,998 | -8% | 1 | 1 | 0% | 2,301 | 4,762 | +107% | 0 | 0 | — |
case-03 | pass→pass | 12,262 | 9,868 | -20% | 1 | 1 | 0% | 1,821 | 4,742 | +160% | 0 | 0 | — |
case-04 | pass→pass | 3,108 | 3,354 | +8% | 1 | 1 | 0% | 541 | 3,379 | +525% | 0 | 0 | — |
case-05 | pass→pass | 4,864 | 3,138 | -35% | 1 | 1 | 0% | 763 | 3,392 | +345% | 0 | 0 | — |
case-06 | pass→pass | 3,696 | 3,575 | -3% | 1 | 1 | 0% | 532 | 3,337 | +527% | 0 | 0 | — |
case-07 | pass→pass | 8,777 | 4,027 | -54% | 1 | 1 | 0% | 1,399 | 3,567 | +155% | 0 | 0 | — |
case-08 | pass→pass | 5,160 | 3,059 | -41% | 1 | 1 | 0% | 887 | 3,334 | +276% | 0 | 0 | — |
case-09 | pass→pass | 14,485 | 12,529 | -14% | 1 | 1 | 0% | 2,225 | 4,897 | +120% | 0 | 0 | — |
case-10 | fail→pass | 16,363 | 7,612 | -53% | 1 | 1 | 0% | 2,675 | 4,094 | +53% | 0 | 0 | — |
case-11 | pass→pass | 4,533 | 3,907 | -14% | 1 | 1 | 0% | 770 | 3,466 | +350% | 0 | 0 | — |
case-12 | pass→pass | 9,358 | 10,607 | +13% | 1 | 1 | 0% | 1,787 | 4,764 | +167% | 0 | 0 | — |
case-13 | pass→pass | 3,525 | 2,761 | -22% | 1 | 1 | 0% | 529 | 3,227 | +510% | 0 | 0 | — |
case-14 | pass→pass | 3,272 | 2,467 | -25% | 1 | 1 | 0% | 598 | 3,240 | +442% | 0 | 0 | — |
case-15 | pass→pass | 2,905 | 2,246 | -23% | 1 | 1 | 0% | 483 | 3,206 | +564% | 0 | 0 | — |
case-16 | fail→pass | 4,465 | 3,131 | -30% | 1 | 1 | 0% | 775 | 3,349 | +332% | 0 | 0 | — |
case-17 | pass→pass | 5,762 | 4,345 | -25% | 1 | 1 | 0% | 1,077 | 3,623 | +236% | 0 | 0 | — |
case-18 | pass→pass | 11,820 | 9,308 | -21% | 1 | 1 | 0% | 2,368 | 4,619 | +95% | 0 | 0 | — |
case-19 | pass→pass | 14,985 | 16,633 | +11% | 1 | 1 | 0% | 2,726 | 5,457 | +100% | 0 | 0 | — |
case-20 | pass→pass | 4,785 | 1,478 | -69% | 1 | 1 | 0% | 806 | 2,993 | +271% | 0 | 0 | — |
case-21 | pass→pass | 4,691 | 3,635 | -23% | 1 | 1 | 0% | 910 | 3,510 | +286% | 0 | 0 | — |
case-22 | pass→pass | 5,064 | 4,817 | -5% | 1 | 1 | 0% | 850 | 3,684 | +333% | 0 | 0 | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +9 percentage points is the difference between those two pass rates over the 22 comparable cases.
Without the skill loaded, the model failed this case. With it loaded, the same prompt on the same model passed. This is one improved case from the latest verified run; every case, including any that regressed, is in the table above.
Other measured skills in the registry, with their headline benchmark lift.