Skip to content

Commit 15d3a45

Browse files
nikhilaravifacebook-github-bot
authored andcommitted
Setup website with docusaurus (facebookresearch#11)
Summary: Set up landing page, docs page, and html versions of the ipython notebook tutorials. Pull Request resolved: fairinternal/pytorch3d#11 Reviewed By: gkioxari Differential Revision: D19730380 Pulled By: nikhilaravi fbshipit-source-id: 5df8d3f2ac2f8dce4d51f5d14fc336508c2fd0ea
1 parent e290f87 commit 15d3a45

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

48 files changed

+1900
-72
lines changed

.gitignore

+13
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,16 @@ build/
22
dist/
33
*.egg-info/
44
**/__pycache__/
5+
6+
# Docusaurus site
7+
website/yarn.lock
8+
website/build/
9+
website/i18n/
10+
website/node_modules/*
11+
website/npm-debug.log
12+
13+
## Generated for tutorials
14+
website/_tutorials/
15+
website/static/files/
16+
website/pages/tutorials/*
17+
!website/pages/tutorials/index.js
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

docs/notes/batching.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,13 @@
1+
---
2+
hide_title: true
3+
sidebar_label: Batching
4+
---
5+
16
# Batching
27

38
In deep learning, every optimization step operates on multiple input examples for robust training. Thus, efficient batching is crucial. For image inputs, batching is straighforward; N images are resized to the same height and width and stacked as a 4 dimensional tensor of shape `N x 3 x H x W`. For meshes, batching is less straighforward.
49

5-
<img src="../figs/batch_intro.png" alt="batch_intro" align="middle"/>
10+
<img src="assets/batch_intro.png" alt="batch_intro" align="middle"/>
611

712
## Batch modes for meshes
813

@@ -12,13 +17,13 @@ Assume you want to construct a batch containing two meshes, with `mesh1 = (v1: V
1217
* Padded: The padded representation constructs a tensor by padding the extra values. Specifically, `meshes.verts_padded()` returns a tensor of shape `2 x max(V1, V2) x 3` and pads the extra vertices with `0`s. Similarly, `meshes.faces_padded()` returns a tensor of shape `2 x max(F1, F2) x 3` and pads the extra faces with `-1`s.
1318
* Packed: The packed representation concatenates the examples in the batch into a tensor. In particular, `meshes.verts_packed()` returns a tensor of shape `(V1 + V2) x 3`. Similarly, `meshes.faces_packed()` returns a tensor of shape `(F1 + F2) x 3` for the faces. In the packed mode, auxiliary variables are computed that enable efficient conversion between packed and padded or list modes.
1419

15-
<img src="../figs/batch_modes.gif" alt="batch_modes" height="450" align="middle" />
20+
<img src="assets/batch_modes.gif" alt="batch_modes" height="450" align="middle" />
1621

1722
## Use cases for batch modes
1823

1924
The need for different mesh batch modes is inherent to the way pytorch operators are implemented. To fully utilize the optimized pytorch ops, the [Meshes][meshes] data structure allows for efficient conversion between the different batch modes. This is crucial when aiming for a fast and efficient training cycle. An example of this is [Mesh R-CNN][meshrcnn]. Here, in the same forward pass different parts of the network assume different inputs, which are computed by converting between the different batch modes. In particular, [vert_align][vert_align] assumes a *padded* input tensor while immediately after [graph_conv][graphconv] assumes a *packed* input tensor.
2025

21-
<img src="../figs/meshrcnn.png" alt="meshrcnn" width="700" align="middle" />
26+
<img src="assets/meshrcnn.png" alt="meshrcnn" width="700" align="middle" />
2227

2328

2429
[meshes]: https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/structures/meshes.py

docs/notes/meshes_io.md

+5
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
---
2+
sidebar_label: Loading from file
3+
hide_title: true
4+
---
5+
16
# Meshes and IO
27

38
The Meshes object represents a batch of triangulated meshes, and is central to

docs/notes/renderer.md

+10-5
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,9 @@
1-
# Differentiable Rendering
1+
---
2+
hide_title: true
3+
sidebar_label: Overview
4+
---
5+
6+
# Rendering Overview
27

38
Differentiable rendering is a relatively new and exciting research area in computer vision, bridging the gap between 2D and 3D by allowing 2D image pixels to be related back to 3D properties of a scene.
49

@@ -18,7 +23,7 @@ Our implementation decouples the rasterization and shading steps of rendering. T
1823

1924
## <u>Get started</u>
2025

21-
To learn about more the implementation and start using the renderer refer to [renderer_getting_started.md](renderer_getting_started.md), which also contains the [architecture overview](../figs/architecture_overview.png) and [coordinate transformation conventions](../figs/transformations_overview.png).
26+
To learn about more the implementation and start using the renderer refer to [renderer_getting_started.md](renderer_getting_started.md), which also contains the [architecture overview](assets/architecture_overview.png) and [coordinate transformation conventions](assets/transformations_overview.png).
2227

2328

2429
## <u>Key features</u>
@@ -37,7 +42,7 @@ We compared PyTorch3d with SoftRasterizer to measure the effect of both these de
3742

3843
This figure shows how the coarse-to-fine strategy for rasterization results in significant speed up compared to naive rasterization for large image size and large mesh sizes.
3944

40-
<img src="../figs/p3d_naive_vs_coarse.png" width="1000">
45+
<img src="assets/p3d_naive_vs_coarse.png" width="1000">
4146

4247

4348
For small mesh and image sizes, the naive approach is slightly faster. We advise that you understand the data you are using and choose the rasterization setting which suits your performance requirements. It is easy to switch between the naive and coarse-to-fine options by adjusting the `bin_size` value when initializing the [rasterization settings](https://github.com/facebookresearch/pytorch3d/blob/master/pytorch3d/renderer/mesh/rasterizer.py#L26).
@@ -50,7 +55,7 @@ This figure shows the effect of the _combination_ of coarse-to-fine rasterizatio
5055

5156
In the SoftRasterizer implementation, in both the forward and backward pass, there is a loop over every single face in the mesh for every pixel in the image. Therefore, the time for the full forward plus backward pass is ~2x the time for the forward pass. For small mesh and image sizes, the SoftRasterizer approach is slightly faster.
5257

53-
<img src="../figs/p3d_vs_softras.png" width="1000">
58+
<img src="assets/p3d_vs_softras.png" width="1000">
5459

5560

5661

@@ -66,7 +71,7 @@ We tested with a range of increasingly large meshes and bin sizes.
6671

6772
**Fig 3: PyTorch3d heterogeneous batching compared with SoftRasterizer**
6873

69-
<img src="../figs/fullset_batch_size_16.png" width="700"/>
74+
<img src="assets/fullset_batch_size_16.png" width="700"/>
7075

7176
This shows that for large meshes and large bin width (i.e. more variation in mesh size in the batch) the heterogeneous batching approach in PyTorch3d is faster than either of the workarounds with SoftRasterizer.
7277

docs/notes/renderer_getting_started.md

+8-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
1+
---
2+
hide_title: true
3+
sidebar_label: Getting Started
4+
---
5+
16
# Renderer Getting Started
27

38
### Architecture Overview
49

510
The renderer is designed to be modular, extensible and support batching and gradients for all inputs. The following figure describes all the components of the rendering pipeline.
611

7-
<img src="../figs/architecture_overview.png" width="1000">
12+
<img src="assets/architecture_overview.png" width="1000">
813

914
##### Fragments
1015

@@ -31,7 +36,7 @@ The differentiable renderer API is experimental and subject to change!.
3136

3237
Rendering requires transformations between several different coordinate frames: world space, view/camera space, NDC space and screen space. At each step it is important to know where the camera is located, how the x,y,z axes are aligned and the possible range of values. The following figure outlines the conventions used PyTorch3d.
3338

34-
<img src="../figs/transformations_overview.png" width="1000">
39+
<img src="assets/transformations_overview.png" width="1000">
3540

3641

3742

@@ -43,7 +48,7 @@ While we tried to emulate several aspects of OpenGL, the NDC coordinate system i
4348

4449
In OpenGL, the camera at the origin is looking along `-z` axis in camera space, but it is looking along the `+z` axis in NDC space.
4550

46-
<img align="center" src="../figs/opengl_coordframes.png" width="300">
51+
<img align="center" src="assets/opengl_coordframes.png" width="300">
4752

4853
---
4954
### A simple renderer

docs/notes/why_pytorch3d.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
hide_title: true
3+
sidebar_label: Why PyTorch3d
4+
---
5+
6+
7+
# Why PyTorch3d
8+
9+
10+
Our goal with PyTorch3D is to help accelerate research at the intersection of deep learning and 3D. 3D data is more complex than 2D images and while working on projects such as [Mesh R-CNN](https://github.com/facebookresearch/meshrcnn) and [C3DPO](https://github.com/facebookresearch/c3dpo_nrsfm), we encountered several challenges including 3D data representation, batching, and speed. We have developed many useful operators and abstractions for working on 3D deep learning and want to share this with the community to drive novel research in this area.
11+
12+
In PyTorch3D we have included efficient 3D operators, heterogeneous batching capabilities, and a modular differentiable rendering API, to equip researchers in this field with a much needed toolkit to implement cutting-edge research with complex 3D inputs.
13+

docs/tutorials/bundle_adjustment.ipynb

+5-14
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,6 @@
1111
"# Copyright (c) Facebook, Inc. and its affiliates. All rights reserved."
1212
]
1313
},
14-
{
15-
"cell_type": "markdown",
16-
"metadata": {},
17-
"source": [
18-
"<a href=\"https://colab.research.google.com/github/facebookresearch/pytorch3d/blob/master/docs/tutorials/bundle_adjustment.ipynb\">\n",
19-
" <img align=\"left\" src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/>\n",
20-
"</a>"
21-
]
22-
},
2314
{
2415
"cell_type": "markdown",
2516
"metadata": {},
@@ -40,10 +31,10 @@
4031
"where $d(g_i, g_j)$ is a suitable metric that compares the extrinsics of cameras $g_i$ and $g_j$. \n",
4132
"\n",
4233
"Visually, the problem can be described as follows. The picture below depicts the situation at the beginning of our optimization. The ground truth cameras are plotted in green while the randomly initialized estimated cameras are plotted in blue:\n",
43-
"![Initialization](./data/bundle_adjustment_initialization.png)\n",
34+
"![Initialization](data/bundle_adjustment_initialization.png)\n",
4435
"\n",
4536
"Our optimization seeks to align the estimated (blue) cameras with the ground truth (green) cameras, by minimizing the discrepancies between pairs of relative cameras. Thus, the solution to the problem should look as follows:\n",
46-
"![Solution](./data/bundle_adjustment_final.png)\n",
37+
"![Solution](data/bundle_adjustment_final.png)\n",
4738
"\n",
4839
"In practice, the camera extrinsics $g_{ij}$ and $g_i$ are represented using objects from the `SfMPerspectiveCameras` class initialized with the corresponding rotation and translation matrices `R_absolute` and `T_absolute` that define the extrinsic parameters $g = (R, T); R \\in SO(3); T \\in \\mathbb{R}^3$. In order to ensure that `R_absolute` is a valid rotation matrix, we represent it using an exponential map (implemented with `so3_exponential_map`) of the axis-angle representation of the rotation `log_R_absolute`.\n",
4940
"\n",
@@ -421,9 +412,9 @@
421412
},
422413
"file_extension": ".py",
423414
"kernelspec": {
424-
"display_name": "pytorch3d (local)",
415+
"display_name": "p3d_dev7",
425416
"language": "python",
426-
"name": "pytorch3d_local"
417+
"name": "p3d_dev7"
427418
},
428419
"language_info": {
429420
"codemirror_mode": {
@@ -435,7 +426,7 @@
435426
"name": "python",
436427
"nbconvert_exporter": "python",
437428
"pygments_lexer": "ipython3",
438-
"version": "3.7.5+"
429+
"version": "3.7.6"
439430
},
440431
"mimetype": "text/x-python",
441432
"name": "python",

docs/tutorials/render_textured_meshes.ipynb

+25-47
Large diffs are not rendered by default.

scripts/build_website.sh

+60
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
#!/bin/bash
2+
# Copyright (c) Facebook, Inc. and its affiliates.
3+
4+
# run this script from the project root using `./scripts/build_docs.sh`
5+
6+
usage() {
7+
echo "Usage: $0 [-b]"
8+
echo ""
9+
echo "Build PyTorch3D documentation."
10+
echo ""
11+
echo " -b Build static version of documentation (otherwise start server)"
12+
echo ""
13+
exit 1
14+
}
15+
16+
BUILD_STATIC=false
17+
18+
while getopts 'hb' flag; do
19+
case "${flag}" in
20+
h)
21+
usage
22+
;;
23+
b)
24+
BUILD_STATIC=true
25+
;;
26+
*)
27+
usage
28+
;;
29+
esac
30+
done
31+
32+
33+
echo "-----------------------------------"
34+
echo "Building PyTorch3d Docusaurus site"
35+
echo "-----------------------------------"
36+
cd website || exit
37+
yarn
38+
cd ..
39+
40+
echo "-----------------------------------"
41+
echo "Generating tutorials"
42+
echo "-----------------------------------"
43+
cwd=$(pwd)
44+
mkdir -p "website/_tutorials"
45+
mkdir -p "website/static/files"
46+
python scripts/parse_tutorials.py --repo_dir "${cwd}"
47+
48+
cd website || exit
49+
50+
if [[ $BUILD_STATIC == true ]]; then
51+
echo "-----------------------------------"
52+
echo "Building static site"
53+
echo "-----------------------------------"
54+
yarn build
55+
else
56+
echo "-----------------------------------"
57+
echo "Starting local server"
58+
echo "-----------------------------------"
59+
yarn start
60+
fi

scripts/parse_tutorials.py

+111
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
#!/usr/bin/env python3
2+
# Copyright (c) Facebook, Inc. and its affiliates.
3+
4+
import argparse
5+
import json
6+
import os
7+
8+
import nbformat
9+
from bs4 import BeautifulSoup
10+
from nbconvert import HTMLExporter, ScriptExporter
11+
12+
13+
TEMPLATE = """const CWD = process.cwd();
14+
15+
const React = require('react');
16+
const Tutorial = require(`${{CWD}}/core/Tutorial.js`);
17+
18+
class TutorialPage extends React.Component {{
19+
render() {{
20+
const {{config: siteConfig}} = this.props;
21+
const {{baseUrl}} = siteConfig;
22+
return <Tutorial baseUrl={{baseUrl}} tutorialID="{}"/>;
23+
}}
24+
}}
25+
26+
module.exports = TutorialPage;
27+
28+
"""
29+
30+
JS_SCRIPTS = """
31+
<script
32+
src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.1.10/require.min.js">
33+
</script>
34+
<script
35+
src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.0.3/jquery.min.js">
36+
</script>
37+
""" # noqa: E501
38+
39+
40+
def gen_tutorials(repo_dir: str) -> None:
41+
"""Generate HTML tutorials for PyTorch3d Docusaurus site from Jupyter notebooks.
42+
43+
Also create ipynb and py versions of tutorial in Docusaurus site for
44+
download.
45+
"""
46+
with open(os.path.join(repo_dir, "website", "tutorials.json"), "r") as infile:
47+
tutorial_config = json.loads(infile.read())
48+
49+
tutorial_ids = {x["id"] for v in tutorial_config.values() for x in v}
50+
51+
for tid in tutorial_ids:
52+
print("Generating {} tutorial".format(tid))
53+
54+
# convert notebook to HTML
55+
ipynb_in_path = os.path.join(repo_dir, "docs", "tutorials", "{}.ipynb".format(tid))
56+
with open(ipynb_in_path, "r") as infile:
57+
nb_str = infile.read()
58+
nb = nbformat.reads(nb_str, nbformat.NO_CONVERT)
59+
60+
# displayname is absent from notebook metadata
61+
nb["metadata"]["kernelspec"]["display_name"] = "python3"
62+
63+
exporter = HTMLExporter()
64+
html, meta = exporter.from_notebook_node(nb)
65+
66+
# pull out html div for notebook
67+
soup = BeautifulSoup(html, "html.parser")
68+
nb_meat = soup.find("div", {"id": "notebook-container"})
69+
del nb_meat.attrs["id"]
70+
nb_meat.attrs["class"] = ["notebook"]
71+
html_out = JS_SCRIPTS + str(nb_meat)
72+
73+
# generate html file
74+
html_out_path = os.path.join(
75+
repo_dir, "website", "_tutorials", "{}.html".format(tid)
76+
)
77+
with open(html_out_path, "w") as html_outfile:
78+
html_outfile.write(html_out)
79+
80+
# generate JS file
81+
script = TEMPLATE.format(tid)
82+
js_out_path = os.path.join(
83+
repo_dir, "website", "pages", "tutorials", "{}.js".format(tid)
84+
)
85+
with open(js_out_path, "w") as js_outfile:
86+
js_outfile.write(script)
87+
88+
# output tutorial in both ipynb & py form
89+
ipynb_out_path = os.path.join(
90+
repo_dir, "website", "static", "files", "{}.ipynb".format(tid)
91+
)
92+
with open(ipynb_out_path, "w") as ipynb_outfile:
93+
ipynb_outfile.write(nb_str)
94+
exporter = ScriptExporter()
95+
script, meta = exporter.from_notebook_node(nb)
96+
py_out_path = os.path.join(
97+
repo_dir, "website", "static", "files", "{}.py".format(tid)
98+
)
99+
with open(py_out_path, "w") as py_outfile:
100+
py_outfile.write(script)
101+
102+
103+
if __name__ == "__main__":
104+
parser = argparse.ArgumentParser(
105+
description="Generate JS, HTML, ipynb, and py files for tutorials."
106+
)
107+
parser.add_argument(
108+
"--repo_dir", metavar="path", required=True, help="Pytorch3D repo directory."
109+
)
110+
args = parser.parse_args()
111+
gen_tutorials(args.repo_dir)

0 commit comments

Comments
 (0)