Skip to content

Commit 532d438

Browse files
authored
Merge branch 'main' into zzb_fsdp_add_event_sync
2 parents d51e39b + 6f54c88 commit 532d438

25 files changed

+622
-383
lines changed

.github/workflows/build-tutorials.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ jobs:
4444
4545
- name: Checkout Tutorials
4646
uses: actions/checkout@v3
47+
with:
48+
fetch-depth: 0
4749

4850
- name: Setup Linux
4951
uses: pytorch/pytorch/.github/actions/setup-linux@main
@@ -115,6 +117,8 @@ jobs:
115117
116118
- name: Checkout Tutorials
117119
uses: actions/checkout@v3
120+
with:
121+
fetch-depth: 0
118122

119123
- name: Setup Linux
120124
uses: pytorch/pytorch/.github/actions/setup-linux@main

.jenkins/insert_last_verified.py

Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
import json
2+
import os
3+
import subprocess
4+
import sys
5+
from datetime import datetime
6+
7+
from bs4 import BeautifulSoup
8+
9+
10+
json_file_path = "tutorials-review-data.json"
11+
12+
# paths to skip from the post-processing script
13+
paths_to_skip = [
14+
"beginner/examples_autograd/two_layer_net_custom_function", # not present in the repo
15+
"beginner/examples_nn/two_layer_net_module", # not present in the repo
16+
"beginner/examples_tensor/two_layer_net_numpy", # not present in the repo
17+
"beginner/examples_tensor/two_layer_net_tensor", # not present in the repo
18+
"beginner/examples_autograd/two_layer_net_autograd", # not present in the repo
19+
"beginner/examples_nn/two_layer_net_optim", # not present in the repo
20+
"beginner/examples_nn/two_layer_net_nn", # not present in the repo
21+
"intermediate/coding_ddpg", # not present in the repo - will delete the carryover
22+
]
23+
# Mapping of source directories to build directories
24+
source_to_build_mapping = {
25+
"beginner": "beginner_source",
26+
"recipes": "recipes_source",
27+
"distributed": "distributed",
28+
"intermediate": "intermediate_source",
29+
"prototype": "prototype_source",
30+
"advanced": "advanced_source",
31+
"": "", # root dir for index.rst
32+
}
33+
34+
def get_git_log_date(file_path, git_log_args):
35+
try:
36+
result = subprocess.run(
37+
["git", "log"] + git_log_args + ["--", file_path],
38+
capture_output=True,
39+
text=True,
40+
check=True,
41+
)
42+
if result.stdout:
43+
date_str = result.stdout.splitlines()[0]
44+
return datetime.strptime(date_str, "%a, %d %b %Y %H:%M:%S %z")
45+
except subprocess.CalledProcessError:
46+
pass
47+
raise ValueError(f"Could not find date for {file_path}")
48+
49+
def get_creation_date(file_path):
50+
return get_git_log_date(file_path, ["--diff-filter=A", "--format=%aD"]).strftime("%b %d, %Y")
51+
52+
53+
def get_last_updated_date(file_path):
54+
return get_git_log_date(file_path, ["-1", "--format=%aD"]).strftime("%b %d, %Y")
55+
56+
# Try to find the source file with the given base path and the extensions .rst and .py
57+
def find_source_file(base_path):
58+
for ext in [".rst", ".py"]:
59+
source_file_path = base_path + ext
60+
if os.path.exists(source_file_path):
61+
return source_file_path
62+
return None
63+
64+
65+
# Function to process a JSON file and insert the "Last Verified" information into the HTML files
66+
def process_json_file(build_dir , json_file_path):
67+
with open(json_file_path, "r", encoding="utf-8") as json_file:
68+
json_data = json.load(json_file)
69+
70+
for entry in json_data:
71+
path = entry["Path"]
72+
last_verified = entry["Last Verified"]
73+
status = entry.get("Status", "")
74+
if path in paths_to_skip:
75+
print(f"Skipping path: {path}")
76+
continue
77+
if status in ["needs update", "not verified"]:
78+
formatted_last_verified = "Not Verified"
79+
elif last_verified:
80+
try:
81+
last_verified_date = datetime.strptime(last_verified, "%Y-%m-%d")
82+
formatted_last_verified = last_verified_date.strftime("%b %d, %Y")
83+
except ValueError:
84+
formatted_last_verified = "Unknown"
85+
else:
86+
formatted_last_verified = "Not Verified"
87+
if status == "deprecated":
88+
formatted_last_verified += "Deprecated"
89+
90+
for build_subdir, source_subdir in source_to_build_mapping.items():
91+
if path.startswith(build_subdir):
92+
html_file_path = os.path.join(build_dir, path + ".html")
93+
base_source_path = os.path.join(
94+
source_subdir, path[len(build_subdir) + 1 :]
95+
)
96+
source_file_path = find_source_file(base_source_path)
97+
break
98+
else:
99+
print(f"Warning: No mapping found for path {path}")
100+
continue
101+
102+
if not os.path.exists(html_file_path):
103+
print(
104+
f"Warning: HTML file not found for path {html_file_path}."
105+
"If this is a new tutorial, please add it to the audit JSON file and set the Verified status and todays's date."
106+
)
107+
continue
108+
109+
if not source_file_path:
110+
print(f"Warning: Source file not found for path {base_source_path}.")
111+
continue
112+
113+
created_on = get_creation_date(source_file_path)
114+
last_updated = get_last_updated_date(source_file_path)
115+
116+
with open(html_file_path, "r", encoding="utf-8") as file:
117+
soup = BeautifulSoup(file, "html.parser")
118+
# Check if the <p> tag with class "date-info-last-verified" already exists
119+
existing_date_info = soup.find("p", {"class": "date-info-last-verified"})
120+
if existing_date_info:
121+
print(
122+
f"Warning: <p> tag with class 'date-info-last-verified' already exists in {html_file_path}"
123+
)
124+
continue
125+
126+
h1_tag = soup.find("h1") # Find the h1 tag to insert the dates
127+
if h1_tag:
128+
date_info_tag = soup.new_tag("p", **{"class": "date-info-last-verified"})
129+
date_info_tag["style"] = "color: #6c6c6d; font-size: small;"
130+
# Add the "Created On", "Last Updated", and "Last Verified" information
131+
date_info_tag.string = (
132+
f"Created On: {created_on} | "
133+
f"Last Updated: {last_updated} | "
134+
f"Last Verified: {formatted_last_verified}"
135+
)
136+
# Insert the new tag after the <h1> tag
137+
h1_tag.insert_after(date_info_tag)
138+
# Save back to the HTML.
139+
with open(html_file_path, "w", encoding="utf-8") as file:
140+
file.write(str(soup))
141+
else:
142+
print(f"Warning: <h1> tag not found in {html_file_path}")
143+
144+
145+
def main():
146+
if len(sys.argv) < 2:
147+
print("Error: Build directory not provided. Exiting.")
148+
exit(1)
149+
build_dir = sys.argv[1]
150+
print(f"Build directory: {build_dir}")
151+
process_json_file(build_dir , json_file_path)
152+
print(
153+
"Finished processing JSON file. Please check the output for any warnings. "
154+
"Pages like `nlp/index.html` are generated only during the full `make docs` "
155+
"or `make html` build. Warnings about these files when you run `make html-noplot` "
156+
"can be ignored."
157+
)
158+
159+
if __name__ == "__main__":
160+
main()

Makefile

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,18 +86,29 @@ download:
8686
wget https://www.cis.upenn.edu/~jshi/ped_html/PennFudanPed.zip -P $(DATADIR)
8787
unzip -o $(DATADIR)/PennFudanPed.zip -d intermediate_source/data/
8888

89+
download-last-reviewed-json:
90+
@echo "Downloading tutorials-review-data.json..."
91+
curl -o tutorials-review-data.json https://raw.githubusercontent.com/pytorch/tutorials/refs/heads/last-reviewed-data-json/tutorials-review-data.json
92+
@echo "Finished downloading tutorials-review-data.json."
8993
docs:
9094
make download
95+
make download-last-reviewed-json
9196
make html
97+
@python .jenkins/insert_last_verified.py $(BUILDDIR)/html
9298
rm -rf docs
9399
cp -r $(BUILDDIR)/html docs
94100
touch docs/.nojekyll
101+
rm -rf tutorials-review-data.json
95102

96103
html-noplot:
97104
$(SPHINXBUILD) -D plot_gallery=0 -b html $(SPHINXOPTS) "$(SOURCEDIR)" "$(BUILDDIR)/html"
98105
# bash .jenkins/remove_invisible_code_block_batch.sh "$(BUILDDIR)/html"
99106
@echo
107+
make download-last-reviewed-json
100108
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
109+
@echo "Running post-processing script to insert 'Last Verified' dates..."
110+
@python .jenkins/insert_last_verified.py $(BUILDDIR)/html
111+
rm -rf tutorials-review-data.json
101112

102113
clean-cache:
103114
make clean

_static/css/custom2.css

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,8 +67,11 @@ input[type="radio"] {
6767
.gsc-control-cse {
6868
padding: 0 !important;
6969
border-radius: 0px !important;
70-
border: none !important;;
71-
overflow: hidden;
70+
border: none !important;
71+
}
72+
73+
.gsc-overflow-hidden {
74+
overflow: visible !important;
7275
}
7376

7477
#___gcse_0 {

advanced_source/cpp_custom_ops.rst

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,9 +63,47 @@ Using ``cpp_extension`` is as simple as writing the following ``setup.py``:
6363
6464
If you need to compile CUDA code (for example, ``.cu`` files), then instead use
6565
`torch.utils.cpp_extension.CUDAExtension <https://pytorch.org/docs/stable/cpp_extension.html#torch.utils.cpp_extension.CUDAExtension>`_.
66-
Please see how
67-
`extension-cpp <https://github.com/pytorch/extension-cpp>`_ for an example for
68-
how this is set up.
66+
Please see `extension-cpp <https://github.com/pytorch/extension-cpp>`_ for an
67+
example for how this is set up.
68+
69+
Starting with PyTorch 2.6, you can now build a single wheel for multiple CPython
70+
versions (similar to what you would do for pure python packages). In particular,
71+
if your custom library adheres to the `CPython Stable Limited API
72+
<https://docs.python.org/3/c-api/stable.html>`_ or avoids CPython entirely, you
73+
can build one Python agnostic wheel against a minimum supported CPython version
74+
through setuptools' ``py_limited_api`` flag, like so:
75+
76+
.. code-block:: python
77+
78+
from setuptools import setup, Extension
79+
from torch.utils import cpp_extension
80+
81+
setup(name="extension_cpp",
82+
ext_modules=[
83+
cpp_extension.CppExtension(
84+
"extension_cpp",
85+
["python_agnostic_code.cpp"],
86+
py_limited_api=True)],
87+
cmdclass={'build_ext': cpp_extension.BuildExtension},
88+
options={"bdist_wheel": {"py_limited_api": "cp39"}}
89+
)
90+
91+
Note that you must specify ``py_limited_api=True`` both within ``setup``
92+
and also as an option to the ``"bdist_wheel"`` command with the minimal supported
93+
Python version (in this case, 3.9). This ``setup`` would build one wheel that could
94+
be installed across multiple Python versions ``python>=3.9``. Please see
95+
`torchao <https://github.com/pytorch/ao>`_ for an example.
96+
97+
.. note::
98+
99+
You must verify independently that the built wheel is truly Python agnostic.
100+
Specifying ``py_limited_api`` does not check for any guarantees, so it is possible
101+
to build a wheel that looks Python agnostic but will crash, or worse, be silently
102+
incorrect, in another Python environment. Take care to avoid using unstable CPython
103+
APIs, for example APIs from libtorch_python (in particular pytorch/python bindings,)
104+
and to only use APIs from libtorch (aten objects, operators and the dispatcher).
105+
For example, to give access to custom ops from Python, the library should register
106+
the ops through the dispatcher (covered below!).
69107

70108
Defining the custom op and adding backend implementations
71109
---------------------------------------------------------
@@ -177,7 +215,7 @@ operator specifies how to compute the metadata of output tensors given the metad
177215
The FakeTensor kernel should return dummy Tensors of your choice with
178216
the correct Tensor metadata (shape/strides/``dtype``/device).
179217

180-
We recommend that this be done from Python via the `torch.library.register_fake` API,
218+
We recommend that this be done from Python via the ``torch.library.register_fake`` API,
181219
though it is possible to do this from C++ as well (see
182220
`The Custom Operators Manual <https://pytorch.org/docs/main/notes/custom_operators.html>`_
183221
for more details).
@@ -188,7 +226,9 @@ for more details).
188226
# before calling ``torch.library`` APIs that add registrations for the
189227
# C++ custom operator(s). The following import loads our
190228
# C++ custom operator definitions.
191-
# See the next section for more details.
229+
# Note that if you are striving for Python agnosticism, you should use
230+
# the ``load_library(...)`` API call instead. See the next section for
231+
# more details.
192232
from . import _C
193233
194234
@torch.library.register_fake("extension_cpp::mymuladd")
@@ -214,7 +254,10 @@ of two ways:
214254
1. If you're following this tutorial, importing the Python C extension module
215255
we created will load the C++ custom operator definitions.
216256
2. If your C++ custom operator is located in a shared library object, you can
217-
also use ``torch.ops.load_library("/path/to/library.so")`` to load it.
257+
also use ``torch.ops.load_library("/path/to/library.so")`` to load it. This
258+
is the blessed path for Python agnosticism, as you will not have a Python C
259+
extension module to import. See `torchao __init__.py <https://github.com/pytorch/ao/blob/881e84b4398eddcea6fee4d911fc329a38b5cd69/torchao/__init__.py#L26-L28>`_
260+
for an example.
218261

219262

220263
Adding training (autograd) support for an operator

advanced_source/cpp_export.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Loading a TorchScript Model in C++
22
=====================================
33

4-
.. note:: TorchScript is no longer in active development.
4+
.. warning:: TorchScript is no longer in active development.
55

66
As its name suggests, the primary interface to PyTorch is the Python
77
programming language. While Python is a suitable and preferred language for

advanced_source/cpp_frontend.rst

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -969,15 +969,15 @@ the data loader every epoch and then write the GAN training code:
969969
discriminator->zero_grad();
970970
torch::Tensor real_images = batch.data;
971971
torch::Tensor real_labels = torch::empty(batch.data.size(0)).uniform_(0.8, 1.0);
972-
torch::Tensor real_output = discriminator->forward(real_images);
972+
torch::Tensor real_output = discriminator->forward(real_images).reshape(real_labels.sizes());
973973
torch::Tensor d_loss_real = torch::binary_cross_entropy(real_output, real_labels);
974974
d_loss_real.backward();
975975
976976
// Train discriminator with fake images.
977977
torch::Tensor noise = torch::randn({batch.data.size(0), kNoiseSize, 1, 1});
978978
torch::Tensor fake_images = generator->forward(noise);
979979
torch::Tensor fake_labels = torch::zeros(batch.data.size(0));
980-
torch::Tensor fake_output = discriminator->forward(fake_images.detach());
980+
torch::Tensor fake_output = discriminator->forward(fake_images.detach()).reshape(fake_labels.sizes());
981981
torch::Tensor d_loss_fake = torch::binary_cross_entropy(fake_output, fake_labels);
982982
d_loss_fake.backward();
983983
@@ -987,7 +987,7 @@ the data loader every epoch and then write the GAN training code:
987987
// Train generator.
988988
generator->zero_grad();
989989
fake_labels.fill_(1);
990-
fake_output = discriminator->forward(fake_images);
990+
fake_output = discriminator->forward(fake_images).reshape(fake_labels.sizes());
991991
torch::Tensor g_loss = torch::binary_cross_entropy(fake_output, fake_labels);
992992
g_loss.backward();
993993
generator_optimizer.step();

advanced_source/torch-script-parallelism.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Dynamic Parallelism in TorchScript
22
==================================
33

4-
.. note:: TorchScript is no longer in active development.
4+
.. warning:: TorchScript is no longer in active development.
55

66
In this tutorial, we introduce the syntax for doing *dynamic inter-op parallelism*
77
in TorchScript. This parallelism has the following properties:

advanced_source/torch_script_custom_classes.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
Extending TorchScript with Custom C++ Classes
22
===============================================
33

4-
.. note:: TorchScript is no longer in active development.
4+
.. warning:: TorchScript is no longer in active development.
55

66
This tutorial is a follow-on to the
77
:doc:`custom operator <torch_script_custom_ops>`

beginner_source/Intro_to_TorchScript_tutorial.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
55
**Authors:** James Reed (jamesreed@fb.com), Michael Suo (suo@fb.com), rev2
66
7-
.. note:: TorchScript is no longer in active development.
7+
.. warning:: TorchScript is no longer in active development.
88
99
This tutorial is an introduction to TorchScript, an intermediate
1010
representation of a PyTorch model (subclass of ``nn.Module``) that

beginner_source/blitz/autograd_tutorial.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -191,23 +191,22 @@
191191
# .. math::
192192
#
193193
#
194-
# J^{T}\cdot \vec{v}=\left(\begin{array}{ccc}
194+
# J^{T}\cdot \vec{v} = m \cdot \left(\begin{array}{ccc}
195195
# \frac{\partial y_{1}}{\partial x_{1}} & \cdots & \frac{\partial y_{m}}{\partial x_{1}}\\
196196
# \vdots & \ddots & \vdots\\
197197
# \frac{\partial y_{1}}{\partial x_{n}} & \cdots & \frac{\partial y_{m}}{\partial x_{n}}
198198
# \end{array}\right)\left(\begin{array}{c}
199199
# \frac{\partial l}{\partial y_{1}}\\
200200
# \vdots\\
201201
# \frac{\partial l}{\partial y_{m}}
202-
# \end{array}\right)=\left(\begin{array}{c}
202+
# \end{array}\right) = m \cdot \left(\begin{array}{c}
203203
# \frac{\partial l}{\partial x_{1}}\\
204204
# \vdots\\
205205
# \frac{\partial l}{\partial x_{n}}
206206
# \end{array}\right)
207207
#
208208
# This characteristic of vector-Jacobian product is what we use in the above example;
209209
# ``external_grad`` represents :math:`\vec{v}`.
210-
#
211210

212211

213212

0 commit comments

Comments
 (0)