Skip to content
This repository was archived by the owner on Jun 10, 2026. It is now read-only.

Commit 0b757b4

Browse files
zhassan223Ziems
andauthored
Skypilot Support (#151)
* Create skypilot_train.yaml * entered template for skypilot job launch * addressed PR comments * removed accelerate to avoid double launching * user doesn't supply accelerate template, but uses it internally still for arbor services * fixed accidental deletion * fix for deepspeed testing on scripts * ruff checks --------- Co-authored-by: Noah Ziems <nziems2@nd.edu>
1 parent f40fd75 commit 0b757b4

7 files changed

Lines changed: 286 additions & 21 deletions

File tree

README.md

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -144,14 +144,6 @@ print(optimized_translate(english="hello"))
144144
```
145145
---
146146

147-
### Accelerate Configuration
148-
149-
For advanced distributed training setups, you can specify a custom [Hugging Face Accelerate](https://huggingface.co/docs/accelerate/) config in your `~/.arbor/config.yaml`:
150-
151-
```yaml
152-
accelerate_config: "/path/to/your/accelerate_config.yaml"
153-
```
154-
155147
---
156148

157149
### Troubleshooting

arbor/core/config.py

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,6 @@ class Config(BaseModel):
1111
# Basic settings
1212
storage_path: str = str(Path.home() / ".arbor" / "storage")
1313

14-
# Training settings
15-
accelerate_config: Optional[str] = None
16-
1714
# Server settings
1815
inactivity_timeout: int = 30
1916

arbor/server/services/jobs/grpo_job.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,6 @@ def _launch_inference_job(
210210
num_processes=num_processes,
211211
main_process_port=main_process_port,
212212
script_args=script_args,
213-
accelerate_config=self.config.accelerate_config,
214213
env=my_env,
215214
log_callback=self.create_log_callback("GRPO"),
216215
)

arbor/utils/process_runner.py

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Clean abstraction for running long-running processes without the Popen ugliness.
33
"""
44

5+
import os
56
import signal
67
import subprocess
78
import sys
@@ -210,43 +211,55 @@ def start_training(
210211
num_processes: int,
211212
main_process_port: int,
212213
script_args: list[str],
213-
accelerate_config: Optional[str] = None,
214214
env: Optional[dict[str, str]] = None,
215215
log_callback: Optional[Callable[[str], None]] = None,
216216
) -> subprocess.Popen:
217217
"""
218-
Start an accelerate-based training process.
218+
Start an accelerate-based training process using the bundled config.
219219
220220
Args:
221-
script_path: Path to the training script
221+
module: The python module to run
222222
num_processes: Number of processes for accelerate
223223
main_process_port: Port for main process
224-
script_args: Arguments to pass to the script (everything after script path)
225-
accelerate_config: Optional accelerate config file path
224+
script_args: Arguments to pass to the script
226225
env: Environment variables
227226
log_callback: Function to call with each log line
228227
"""
228+
# Path to the bundled deepspeed config within the project
229+
project_root = Path(__file__).resolve().parent.parent.parent
230+
accelerate_config = str(project_root / "configs" / "deepspeed_config.yaml")
231+
229232
command = [
230233
sys.executable,
231234
"-m",
232235
"accelerate.commands.launch",
236+
"--config_file",
237+
accelerate_config,
233238
"--num_processes",
234239
str(num_processes),
235240
"--main_process_port",
236241
str(main_process_port),
237242
]
238243

239-
if accelerate_config:
240-
command.extend(["--config_file", accelerate_config])
241-
242244
command.extend(["--module", module])
243245

244246
if script_args:
245247
# Separator required so accelerate forwards these to the module
246248
command.append("--")
247249
command.extend(script_args)
248250

249-
return self.start(command, env=env, log_callback=log_callback)
251+
# Ensure a stable, unique rendezvous port is used for torch.distributed
252+
runtime_env = dict(os.environ)
253+
if env:
254+
runtime_env.update(env)
255+
# Pin MASTER_ADDR/MASTER_PORT and Accelerate's port to the provided main_process_port
256+
runtime_env.setdefault("MASTER_ADDR", "127.0.0.1")
257+
runtime_env["MASTER_PORT"] = str(main_process_port)
258+
runtime_env["ACCELERATE_TORCH_DISTRIBUTED_PORT"] = str(main_process_port)
259+
# Optionally keep torch distributed debug noise off unless explicitly enabled by caller
260+
runtime_env.setdefault("TORCH_DISTRIBUTED_DEBUG", "OFF")
261+
262+
return self.start(command, env=runtime_env, log_callback=log_callback)
250263

251264
def start_training_from_full_command(
252265
self,

configs/deepspeed_config.yaml

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
compute_environment: LOCAL_MACHINE
2+
debug: false
3+
deepspeed_config:
4+
deepspeed_multinode_launcher: standard
5+
offload_optimizer_device: none
6+
offload_param_device: none
7+
zero3_init_flag: true
8+
zero3_save_16bit_model: true
9+
zero_stage: 3
10+
bf16:
11+
enabled: auto
12+
fp16:
13+
enabled: auto
14+
distributed_type: DEEPSPEED
15+
downcast_bf16: 'no'
16+
machine_rank: 0
17+
main_training_function: main
18+
mixed_precision: no
19+
num_machines: 1
20+
# num_processes: 4 //infer from command line
21+
rdzv_backend: static
22+
same_network: true
23+
tpu_env: []
24+
tpu_use_cluster: false
25+
tpu_use_sudo: false
26+
use_cpu: false

deploy/README.md

Lines changed: 189 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,189 @@
1+
# Arbor Deployment Guide
2+
3+
This directory contains SkyPilot configurations for running Arbor GRPO training jobs on cloud infrastructure.
4+
5+
## Quick Start
6+
7+
### Prerequisites
8+
9+
- [SkyPilot](https://skypilot.readthedocs.io/) installed: `pip install skypilot[aws]` (or your cloud provider)
10+
- AWS/GCP/other cloud credentials configured
11+
- An S3 bucket (or equivalent) for storing checkpoints
12+
13+
### Running Any Training Script
14+
15+
The `skypilot_example.yaml` configuration is designed to work with any Python training script. Scripts run from the project root directory, so use paths relative to root (e.g., `examples/your_script.py`).
16+
17+
#### Step 1: Configure Your Training Script
18+
19+
```bash
20+
sky jobs launch -n training-job deploy/skypilot_example.yaml \
21+
--env TRAINING_SCRIPT=examples/your_script.py \
22+
--infra aws
23+
```
24+
25+
**Example:**
26+
```bash
27+
sky jobs launch -n banking-training deploy/skypilot_example.yaml \
28+
--env TRAINING_SCRIPT=examples/banking_grpo.py \
29+
--infra aws
30+
```
31+
32+
#### Step 2: Configure Your Checkpoint S3 Bucket
33+
34+
Edit `skypilot_example.yaml` and update the checkpoint bucket path (around line 25):
35+
36+
```yaml
37+
file_mounts:
38+
/mnt/checkpoints:
39+
source: s3://your-bucket-name/ # Change this to your S3 bucket
40+
mode: MOUNT_CACHED
41+
```
42+
43+
Replace `s3://your-bucket-name/` with your actual S3 bucket path. The bucket should already exist and be accessible with your cloud credentials.
44+
45+
#### Step 3: Customize Setup (if needed)
46+
47+
If your script requires additional dependencies or data downloads, edit the `setup` section in `skypilot_example.yaml`:
48+
49+
```yaml
50+
setup: |
51+
# ... common setup ...
52+
53+
# Add your script-specific dependencies:
54+
uv pip install package-name
55+
56+
# Add your script-specific data downloads:
57+
curl -Ls https://example.com/data.tar.gz | tar -xz -C examples
58+
```
59+
60+
**Example for `multihop_dev.py`:**
61+
```yaml
62+
setup: |
63+
# ... common setup ...
64+
uv pip install ujson bm25s PyStemmer "jax[cpu]"
65+
curl -Ls https://huggingface.co/dspy/cache/resolve/main/wiki.abstracts.2017.tar.gz | tar -xz -C examples
66+
```
67+
68+
#### Step 4: Launch the Training Job
69+
70+
```bash
71+
sky jobs launch -n training-job deploy/skypilot_example.yaml --infra <aws|gcp|nebius|lambda>
72+
```
73+
74+
Replace `<aws|gcp|nebius|lambda>` with your cloud provider.
75+
76+
#### Step 5: Monitor Progress
77+
78+
```bash
79+
# View logs
80+
sky logs training-job
81+
82+
# Check job status
83+
sky status
84+
```
85+
86+
#### Step 6: Stop the Job (if needed)
87+
88+
```bash
89+
sky jobs cancel training-job
90+
```
91+
92+
## Configuration Details
93+
94+
### Resources
95+
96+
- **GPUs**: 4x L40S GPUs by default (adjust based on your script's needs)
97+
- **Spot Instances**: Disabled by default (`use_spot: false`). Set to `true` for cost savings
98+
- **Disk**: 256 GB
99+
100+
### DeepSpeed Configuration
101+
102+
The training uses DeepSpeed ZeRO-3 (configured in `../configs/deepspeed_config.yaml`):
103+
104+
### What Gets Installed
105+
106+
The setup script automatically installs:
107+
- Project dependencies via `uv sync`
108+
- Common packages: `datasets`, `deepspeed`, `accelerate`
109+
110+
You can add script-specific dependencies in the setup section.
111+
112+
## Examples
113+
114+
### Running multihop_dev.py
115+
116+
1. Edit `skypilot_example.yaml` setup section to uncomment multihop-specific setup:
117+
```yaml
118+
uv pip install ujson bm25s PyStemmer "jax[cpu]"
119+
curl -Ls https://huggingface.co/dspy/cache/resolve/main/wiki.abstracts.2017.tar.gz | tar -xz -C examples
120+
```
121+
122+
2. The script path is already set to `examples/multihop_dev.py` by default
123+
124+
3. Launch:
125+
```bash
126+
sky jobs launch -n multihop-dev deploy/skypilot_example.yaml --infra aws
127+
```
128+
129+
### Running banking_grpo.py
130+
131+
1. Edit the script path in the run section:
132+
```yaml
133+
TRAINING_SCRIPT=${TRAINING_SCRIPT:-examples/banking_grpo.py}
134+
```
135+
136+
2. Launch (without accelerate, since it doesn't need distributed training):
137+
```bash
138+
sky jobs launch -n banking-training deploy/skypilot_example.yaml --infra aws
139+
```
140+
141+
Or if you want to use accelerate anyway:
142+
```bash
143+
sky jobs launch -n banking-training deploy/skypilot_example.yaml \
144+
--env TRAINING_SCRIPT=examples/banking_grpo.py \
145+
--env USE_ACCELERATE=true \
146+
--infra aws
147+
```
148+
149+
No additional setup needed - it only uses standard dependencies.
150+
151+
## Customization
152+
153+
### Changing GPU Count
154+
155+
To use a different number of GPUs, modify `skypilot_example.yaml`:
156+
157+
```yaml
158+
resources:
159+
accelerators: L40S:4 # Change number as needed
160+
```
161+
162+
**Note**: If you change the GPU count and your script uses accelerate, make sure the number matches your script's expectations.
163+
164+
### Using Spot Instances
165+
166+
For cost savings, enable spot instances:
167+
168+
```yaml
169+
resources:
170+
use_spot: true
171+
```
172+
173+
### Changing Cloud Providers
174+
175+
SkyPilot supports multiple providers. Specify during launch:
176+
177+
```bash
178+
sky jobs launch -n training-job deploy/skypilot_example.yaml --infra aws
179+
sky jobs launch -n training-job deploy/skypilot_example.yaml --infra gcp
180+
sky jobs launch -n training-job deploy/skypilot_example.yaml --infra azure
181+
```
182+
183+
184+
185+
## Additional Resources
186+
187+
- [SkyPilot Documentation](https://skypilot.readthedocs.io/)
188+
- [DeepSpeed Documentation](https://www.deepspeed.ai/)
189+
- [Arbor Documentation](../README.md)

deploy/skypilot_example.yaml

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Run the full multihop training
2+
#
3+
# Launch:
4+
# sky jobs launch -n multihop-dev deploy/skypilot_train.yaml --infra <aws|gcp|nebius|lambda|etc>
5+
#
6+
# Monitor progress:
7+
# sky logs multihop-dev
8+
#
9+
# This will train the model using 4x L40S GPUs and save results to S3.
10+
11+
name: arbor-multihop-train
12+
13+
resources:
14+
accelerators: L40S:4
15+
use_spot: true
16+
disk_size: 256
17+
18+
file_mounts:
19+
/mnt/checkpoints:
20+
source: s3://arbor-multihop-checkpoints/
21+
mode: MOUNT_CACHED
22+
23+
#envs:
24+
# Fill in your wandb key: copy from https://wandb.ai/authorize
25+
# Alternatively, you can use `--env WANDB_API_KEY=$WANDB_API_KEY`
26+
# to pass the key in the command line, during `sky jobs launch`.
27+
# WANDB_API_KEY:
28+
29+
workdir: .
30+
31+
setup: |
32+
echo "Begin setup..."
33+
curl -LsSf https://astral.sh/uv/install.sh | sh
34+
export PATH="$HOME/.local/bin:$PATH"
35+
uv sync
36+
echo "Installing dependencies unique to multihop-dev..."
37+
uv pip install ujson
38+
uv pip install bm25s
39+
uv pip install PyStemmer
40+
uv pip install "jax[cpu]"
41+
uv pip install datasets==3.6.0
42+
echo "Downloading wiki.abstracts.2017.tar.gz from HuggingFace..."
43+
curl -Ls https://huggingface.co/dspy/cache/resolve/main/wiki.abstracts.2017.tar.gz | tar -xz -C examples
44+
45+
run: |
46+
echo "Begin run..."
47+
cd examples/
48+
uv run python multihop_dev.py
49+
echo "End run..."

0 commit comments

Comments
 (0)