Skip to content

Commit 6c70c8f

Browse files
authored
Merge branch 'main' into getting-started
2 parents c410375 + aa59857 commit 6c70c8f

File tree

31 files changed

+621
-440
lines changed

31 files changed

+621
-440
lines changed

.github/workflows/gpu_test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: GPU tests
1+
name: GPU Tests
22

33
on:
44
schedule:

.github/workflows/unit_test.yaml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
name: Unit Test
1+
name: Unit Tests
22

33
on:
44
pull_request:
5-
5+
push:
6+
branches: [ main ]
7+
workflow_dispatch:
68

79
jobs:
810
unit_tests:

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
# <img width="35" height="35" alt="image" src="https://github.com/user-attachments/assets/2700a971-e5d6-4036-b03f-2f89c9791609" /> Forge
22

3-
43
#### A PyTorch-native agentic RL library that lets you focus on algorithms—not infra.
4+
[![Unit Tests](https://github.com/meta-pytorch/forge/actions/workflows/unit_test.yaml/badge.svg?branch=main)](https://github.com/meta-pytorch/forge/actions/workflows/unit_test.yaml?query=branch%3Amain)
5+
[![GPU Tests](https://github.com/meta-pytorch/forge/actions/workflows/gpu_test.yaml/badge.svg?branch=main)](https://github.com/meta-pytorch/forge/actions/workflows/gpu_test.yaml?query=branch%3Amain)
56

67
## Overview
78
The primary purpose of the Forge ecosystem is to delineate infra concerns from model concerns thereby making RL experimentation easier. Forge delivers this by providing clear RL abstractions and one scalable implementation of these abstractions. When you need fine-grained control over placement, fault handling/redirecting training loads during a run, or communication patterns, the primitives are there. When you don’t, you can focus purely on your RL algorithm.

apps/grpo/main.py

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -496,22 +496,6 @@ async def continuous_training():
496496

497497
training_task.cancel()
498498

499-
# give mlogger time to shutdown backends, otherwise they can stay running.
500-
# TODO (felipemello) find more elegant solution
501-
await mlogger.shutdown.call_one()
502-
await asyncio.sleep(2)
503-
504-
await asyncio.gather(
505-
DatasetActor.shutdown(dataloader),
506-
policy.shutdown(),
507-
RLTrainer.shutdown(trainer),
508-
ReplayBuffer.shutdown(replay_buffer),
509-
ComputeAdvantages.shutdown(compute_advantages),
510-
ref_model.shutdown(),
511-
reward_actor.shutdown(),
512-
)
513-
# TODO - add a global shutdown that implicitly shuts down all services
514-
# and remote allocations
515499
await shutdown()
516500

517501

docs/Tutorials/ReadMe.MD

Lines changed: 0 additions & 19 deletions
This file was deleted.

docs/source/_static/logo-icon.svg

Lines changed: 12 additions & 0 deletions
Loading

docs/source/conf.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,8 @@ def get_version_path():
6565
"sphinx_gallery.gen_gallery",
6666
]
6767

68+
html_favicon = "_static/logo-icon.svg"
69+
6870
html_baseurl = (
6971
f"https://meta-pytorch.org/forge/{version_path}" # needed for sphinx-sitemap
7072
)
@@ -82,8 +84,14 @@ def get_version_path():
8284
"_templates",
8385
os.path.join(os.path.dirname(pytorch_sphinx_theme2.__file__), "templates"),
8486
]
85-
exclude_patterns = ["tutorials/index.rst", "tutorials/template_tutorial.rst"]
8687

88+
exclude_patterns = [
89+
"tutorials/index.rst",
90+
"tutorials/template_tutorial.rst",
91+
"tutorials/**/index.rst",
92+
"tutorial_sources/**/*.md", # Exclude all markdown files from tutorial_sources
93+
"tutorial_sources/**/*.MD", # Also exclude uppercase .MD files
94+
]
8795
html_static_path = ["_static"]
8896
html_css_files = ["custom.css"]
8997
html_js_files = ["custom.js"]
@@ -168,6 +176,9 @@ def get_version_path():
168176
"substitution",
169177
]
170178

179+
# Configure MyST parser to treat mermaid code blocks as mermaid directives
180+
myst_fence_as_directive = ["mermaid"]
181+
171182
autodoc_default_options = {
172183
"members": True,
173184
"undoc-members": True,
@@ -205,14 +216,15 @@ def get_version_path():
205216
sphinx_gallery_conf = {
206217
"examples_dirs": "tutorial_sources", # Path to examples directory
207218
"gallery_dirs": "tutorials", # Path to generate gallery
208-
"filename_pattern": ".*", # Include all files
219+
"filename_pattern": r".*\.py$", # Only process .py files, not .md files
209220
"download_all_examples": False,
210221
"first_notebook_cell": "%matplotlib inline",
211222
"plot_gallery": "True",
212223
"promote_jupyter_magic": True,
213224
"backreferences_dir": None,
214225
"show_signature": False,
215226
"write_computation_times": False,
227+
"ignore_pattern": r".*\.md$|.*\.MD$", # Explicitly ignore markdown files
216228
}
217229

218230

@@ -223,5 +235,42 @@ def clean_docstring_indentation(app, what, name, obj, options, lines):
223235
lines.append("")
224236

225237

238+
def copy_markdown_tutorials(app):
239+
"""Copy markdown files from tutorial_sources to tutorials directory.
240+
241+
This runs after the builder is initialized but before sphinx-gallery processes files,
242+
ensuring markdown files are available alongside generated .py tutorials.
243+
"""
244+
import shutil
245+
from pathlib import Path
246+
247+
source_dir = Path(app.srcdir) / "tutorial_sources"
248+
target_dir = Path(app.srcdir) / "tutorials"
249+
250+
# Ensure target directory exists
251+
target_dir.mkdir(parents=True, exist_ok=True)
252+
253+
# Walk through tutorial_sources and copy all .md files
254+
for md_file in source_dir.rglob("*.md"):
255+
# Skip README files
256+
if md_file.name.lower() in ["readme.md", "readme.txt"]:
257+
continue
258+
259+
# Calculate relative path from tutorial_sources
260+
rel_path = md_file.relative_to(source_dir)
261+
262+
# Create target path in tutorials directory
263+
target_path = target_dir / rel_path
264+
target_path.parent.mkdir(parents=True, exist_ok=True)
265+
266+
# Copy the file
267+
shutil.copy2(md_file, target_path)
268+
print(
269+
f"[Forge Docs] Copied {md_file.name} to {target_path.relative_to(app.srcdir)}"
270+
)
271+
272+
226273
def setup(app):
227274
app.connect("autodoc-process-docstring", clean_docstring_indentation)
275+
# Use builder-inited to ensure it runs before source files are read
276+
app.connect("builder-inited", copy_markdown_tutorials)

docs/source/index.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,16 @@ TorchForge has been validated in real-world deployments:
224224
```{tip}
225225
Before starting significant work, signal your intention in the issue tracker to coordinate with maintainers.
226226
```
227+
* **Post-Training Focus**: Specializes in techniques
228+
like Supervised Fine-Tuning (SFT) and Group Relative Policy Optimization (GRPO)
229+
* **PyTorch Integration**: Built natively on PyTorch with
230+
dependencies on [PyTorch nightly](https://pytorch.org/get-started/locally/),
231+
[Monarch](https://meta-pytorch.org/monarch), [vLLM](https://docs.vllm.ai/en/latest/),
232+
and [TorchTitan](https://github.com/pytorch/torchtitan).
233+
* **Multi-GPU Support**: Designed for distributed training
234+
with minimum 3 GPU requirement for GRPO training
235+
* **Model Support**: Includes pre-configured setups for popular models
236+
like Llama3 8B and Qwen3.1 7B
227237

228238
```{toctree}
229239
:maxdepth: 2

docs/Tutorials/1_RL_and_Forge_Fundamentals.MD renamed to docs/source/tutorial_sources/zero-to-forge/1_RL_and_Forge_Fundamentals.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ Here's the key insight: **Each RL component becomes a Forge service**. The toy e
7676
```mermaid
7777
graph LR
7878
subgraph Concepts["RL Concepts"]
79+
direction TB
7980
C1["Dataset"]
8081
C2["Policy"]
8182
C3["Reward Model"]
@@ -85,6 +86,7 @@ graph LR
8586
end
8687
8788
subgraph Services["Forge Services (Real Classes)"]
89+
direction TB
8890
S1["DatasetActor"]
8991
S2["Policy"]
9092
S3["RewardActor"]
@@ -392,4 +394,4 @@ score = await reward_actor.evaluate_response.route(
392394

393395
This is fundamentally different from monolithic RL implementations where any component failure stops everything!
394396

395-
In the next Section, we will go a layer deeper and learn how ForgeServices work. Continue to [Part 2 here](./2_Forge_Internals.MD)
397+
In the next Section, we will go a layer deeper and learn how ForgeServices work. Continue to [Part 2 here](./2_Forge_Internals.md)

docs/Tutorials/2_Forge_Internals.MD renamed to docs/source/tutorial_sources/zero-to-forge/2_Forge_Internals.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Part 2: Peeling Back the Abstraction - What Are Services?
22

3-
We highly recommend reading [Part 1](./1_RL_and_Forge_Fundamentals.MD) before this, it explains RL Concepts and how they land in Forge.
3+
We highly recommend reading [Part 1](./1_RL_and_Forge_Fundamentals) before this, it explains RL Concepts and how they land in Forge.
44

55
Now that you see the power of the service abstraction, let's understand what's actually happening under the hood, Grab your chai!
66

@@ -668,4 +668,4 @@ print("All services shut down successfully!")
668668

669669
This is the power of the service abstraction - complex distributed coordination looks like simple async Python code.
670670

671-
In the next part we will learn about [Monarch internals](./3_Monarch_101.MD)
671+
In the next part we will learn about [Monarch internals](./3_Monarch_101.md)

0 commit comments

Comments
 (0)