From 16dd40417f5d7f5807f5029c30fcd3b77d60a64c Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Thu, 8 Apr 2021 17:27:26 +0100 Subject: [PATCH 01/14] WIP --- docs/Makefile | 2 +- docs/requirements.txt | 4 +++ docs/source/conf.py | 8 ++++++ docs/source/index.rst | 6 +++++ docs/source/transforms.rst | 10 ++++++++ gallery/README.rst | 4 +++ gallery/plot_transforms.py | 50 ++++++++++++++++++++++++++++++++++++++ 7 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 gallery/README.rst create mode 100644 gallery/plot_transforms.py diff --git a/docs/Makefile b/docs/Makefile index 1cacf08002f..d8c9de8cab9 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = -W # turn warnings into errors +SPHINXOPTS = # turn warnings into errors SPHINXBUILD = sphinx-build SPHINXPROJ = torchvision SOURCEDIR = source diff --git a/docs/requirements.txt b/docs/requirements.txt index f649853cd03..ef7bc279819 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,3 +1,7 @@ sphinx==1.7.3 +sphinx-gallery +scikit-image +matplotlib +numpy sphinxcontrib-googleanalytics -e git+git://github.com/pytorch/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme diff --git a/docs/source/conf.py b/docs/source/conf.py index 606bc34f841..8cb3b277052 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -60,8 +60,16 @@ def _googleanalytics_setup_wrapper(app): 'sphinx.ext.napoleon', 'sphinx.ext.viewcode', 'sphinxcontrib.googleanalytics', + 'sphinx_gallery.gen_gallery', ] +sphinx_gallery_conf = { + 'examples_dirs': '../../gallery/', # path to your example scripts + 'gallery_dirs': 'auto_examples', # path to where to save gallery generated output + 'backreferences_dir': 'gen_modules/backreferences', + 'doc_module' : ('torchvision',), +} + napoleon_use_ivar = True napoleon_numpy_docstring = False napoleon_google_docstring = True diff --git a/docs/source/index.rst b/docs/source/index.rst index d4aefafed1d..61cb573c96f 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -38,6 +38,12 @@ architectures, and common image transformations for computer vision. transforms utils +.. toctree:: + :maxdepth: 1 + :caption: Examples + + auto_examples/index + .. automodule:: torchvision :members: diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index 6efc2dba5a2..ffec77ea38b 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -76,6 +76,11 @@ Transforms on PIL Image and torch.\*Tensor .. autoclass:: Pad :members: +.. include:: gen_modules/backreferences/torchvision.transforms.Pad.examples +.. raw:: html + +
+ .. autoclass:: RandomAffine :members: @@ -108,6 +113,11 @@ Transforms on PIL Image and torch.\*Tensor .. autoclass:: Resize :members: +.. include:: gen_modules/backreferences/torchvision.transforms.Resize.examples +.. raw:: html + +
+ .. autoclass:: Scale :members: diff --git a/gallery/README.rst b/gallery/README.rst new file mode 100644 index 00000000000..319052106b5 --- /dev/null +++ b/gallery/README.rst @@ -0,0 +1,4 @@ +Example gallery +=============== + +Below is a gallery of examples \ No newline at end of file diff --git a/gallery/plot_transforms.py b/gallery/plot_transforms.py new file mode 100644 index 00000000000..05248242045 --- /dev/null +++ b/gallery/plot_transforms.py @@ -0,0 +1,50 @@ +""" +========================== +Illustration of transforms +========================== + +This file illustrates how torchvision transforms work on some images. + +(Note: this is super WIP) +""" + +#################################### +# Pad +# --- +# +# The :class:`~torchvision.transforms.Pad` transform is super cool + +# from PIL import Image +# import matplotlib.pyplot as plt +# plt.plot([1,2,3,4]) +from PIL import Image, ImageMath +from skimage.data import astronaut +import matplotlib.pyplot as plt +import numpy as np +from torchvision.transforms import Pad + +img = Image.fromarray(astronaut()) + +plt.figure().suptitle("Before padding") +plt.imshow(np.asarray(img)) + +padded_img = Pad(padding=30)(img) +plt.figure().suptitle("After padding") +plt.imshow(np.asarray(padded_img)) + +#################################### +# Resize +# ------ +# +# The :class:`~torchvision.transforms.Resize` transform is even cooler + +from torchvision.transforms import Resize +plt.figure().suptitle("Before resize") +plt.imshow(np.asarray(img)) + +padded_img = Resize(size=30)(img) +plt.figure().suptitle("After resize") +plt.imshow(np.asarray(padded_img)) + + +print(np.exp(3)) \ No newline at end of file From 42245dfe71c448269af9d56cea773d427170b3f4 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Wed, 14 Apr 2021 16:12:20 +0100 Subject: [PATCH 02/14] put back error on warnings for sphinx --- docs/Makefile | 2 +- torchvision/ops/deform_conv.py | 15 ++++++--------- torchvision/transforms/functional.py | 28 ++++++++++++++-------------- 3 files changed, 21 insertions(+), 24 deletions(-) diff --git a/docs/Makefile b/docs/Makefile index 67c067a3862..1cacf08002f 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = # -W # turn warnings into errors +SPHINXOPTS = -W # turn warnings into errors SPHINXBUILD = sphinx-build SPHINXPROJ = torchvision SOURCEDIR = source diff --git a/torchvision/ops/deform_conv.py b/torchvision/ops/deform_conv.py index 7f8760fa35f..7dceee96f27 100644 --- a/torchvision/ops/deform_conv.py +++ b/torchvision/ops/deform_conv.py @@ -29,24 +29,21 @@ def deform_conv2d( Args: input (Tensor[batch_size, in_channels, in_height, in_width]): input tensor - offset (Tensor[batch_size, 2 * offset_groups * kernel_height * kernel_width, - out_height, out_width]): offsets to be applied for each position in the - convolution kernel. - weight (Tensor[out_channels, in_channels // groups, kernel_height, kernel_width]): - convolution weights, split into groups of size (in_channels // groups) + offset (Tensor[batch_size, 2 * offset_groups * kernel_height * kernel_width, out_height, out_width]): + offsets to be applied for each position in the convolution kernel. + weight (Tensor[out_channels, in_channels // groups, kernel_height, kernel_width]): convolution weights, + split into groups of size (in_channels // groups) bias (Tensor[out_channels]): optional bias of shape (out_channels,). Default: None stride (int or Tuple[int, int]): distance between convolution centers. Default: 1 padding (int or Tuple[int, int]): height/width of padding of zeroes around each image. Default: 0 dilation (int or Tuple[int, int]): the spacing between kernel elements. Default: 1 - mask (Tensor[batch_size, offset_groups * kernel_height * kernel_width, - out_height, out_width]): masks to be applied for each position in the - convolution kernel. Default: None + mask (Tensor[batch_size, offset_groups * kernel_height * kernel_width, out_height, out_width]): + masks to be applied for each position in the convolution kernel. Default: None Returns: Tensor[batch_sz, out_channels, out_h, out_w]: result of convolution - Examples:: >>> input = torch.rand(4, 3, 10, 10) >>> kh, kw = 3, 3 diff --git a/torchvision/transforms/functional.py b/torchvision/transforms/functional.py index b365c7df3f3..db1adc06740 100644 --- a/torchvision/transforms/functional.py +++ b/torchvision/transforms/functional.py @@ -744,8 +744,8 @@ def adjust_brightness(img: Tensor, brightness_factor: float) -> Tensor: Args: img (PIL Image or Tensor): Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. + If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. brightness_factor (float): How much to adjust the brightness. Can be any non negative number. 0 gives a black image, 1 gives the original image while 2 increases the brightness by a factor of 2. @@ -764,8 +764,8 @@ def adjust_contrast(img: Tensor, contrast_factor: float) -> Tensor: Args: img (PIL Image or Tensor): Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. + If img is torch Tensor, it is expected to be in [..., 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. contrast_factor (float): How much to adjust the contrast. Can be any non negative number. 0 gives a solid gray image, 1 gives the original image while 2 increases the contrast by a factor of 2. @@ -784,8 +784,8 @@ def adjust_saturation(img: Tensor, saturation_factor: float) -> Tensor: Args: img (PIL Image or Tensor): Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. + If img is torch Tensor, it is expected to be in [..., 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. saturation_factor (float): How much to adjust the saturation. 0 will give a black and white image, 1 will give the original image while 2 will enhance the saturation by a factor of 2. @@ -815,9 +815,9 @@ def adjust_hue(img: Tensor, hue_factor: float) -> Tensor: Args: img (PIL Image or Tensor): Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. - If img is PIL Image mode "1", "L", "I", "F" and modes with transparency (alpha channel) are not supported. + If img is torch Tensor, it is expected to be in [..., 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. + If img is PIL Image mode "1", "L", "I", "F" and modes with transparency (alpha channel) are not supported. hue_factor (float): How much to shift the hue channel. Should be in [-0.5, 0.5]. 0.5 and -0.5 give complete reversal of hue channel in HSV space in positive and negative direction respectively. @@ -848,9 +848,9 @@ def adjust_gamma(img: Tensor, gamma: float, gain: float = 1) -> Tensor: Args: img (PIL Image or Tensor): PIL Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. - If img is PIL Image, modes with transparency (alpha channel) are not supported. + If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. + If img is PIL Image, modes with transparency (alpha channel) are not supported. gamma (float): Non negative real number, same as :math:`\gamma` in the equation. gamma larger than 1 make the shadows darker, while gamma smaller than 1 make dark regions lighter. @@ -1286,8 +1286,8 @@ def adjust_sharpness(img: Tensor, sharpness_factor: float) -> Tensor: Args: img (PIL Image or Tensor): Image to be adjusted. - If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, - where ... means it can have an arbitrary number of leading dimensions. + If img is torch Tensor, it is expected to be in [..., 1 or 3, H, W] format, + where ... means it can have an arbitrary number of leading dimensions. sharpness_factor (float): How much to adjust the sharpness. Can be any non negative number. 0 gives a blurred image, 1 gives the original image while 2 increases the sharpness by a factor of 2. From a06a34c5ebe932369ed5e46dc21f209fccc2ed05 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Wed, 14 Apr 2021 16:15:30 +0100 Subject: [PATCH 03/14] temporarily remove backlings --- docs/source/transforms.rst | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/docs/source/transforms.rst b/docs/source/transforms.rst index 1e726432f23..21e2c152626 100644 --- a/docs/source/transforms.rst +++ b/docs/source/transforms.rst @@ -95,11 +95,6 @@ Transforms on PIL Image and torch.\*Tensor .. autoclass:: Pad :members: -.. include:: gen_modules/backreferences/torchvision.transforms.Pad.examples -.. raw:: html - -
- .. autoclass:: RandomAffine :members: @@ -132,11 +127,6 @@ Transforms on PIL Image and torch.\*Tensor .. autoclass:: Resize :members: -.. include:: gen_modules/backreferences/torchvision.transforms.Resize.examples -.. raw:: html - -
- .. autoclass:: Scale :members: From 3fd623a47e1a11f6f3b354db7334e90827607d78 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Wed, 14 Apr 2021 16:30:59 +0100 Subject: [PATCH 04/14] updated gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index e6e4e0f3728..915fe5b0f78 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,8 @@ torchvision/version.py */**/*~ *~ docs/build +docs/source/auto_examples/ +docs/source/gen_modules/ .coverage htmlcov .*.swp From 08f22a4cce4f95c3f68cc187da9200c2a898007a Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Thu, 15 Apr 2021 17:46:14 +0100 Subject: [PATCH 05/14] not not pround of that one --- docs/source/conf.py | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1138f25769b..7b67b2dc33d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -256,3 +256,30 @@ def handle_item(fieldarg, content): TypedField.make_field = patched_make_field + + +def inject_minigalleries(app, what, name, obj, options, lines): + """Inject minigallery into docstrings. + + This callback is called after the .. auto directives (like ..autoclass) have been processed, + and modifies the lines parameter inplace to add the .. minigallery that will show which examples + are using which object. + + It's a bit hacky, but not *that* hacky when you consider that the recommended way is to do pretty much the same, + but instead with templates using autosummary (which we don't want to use): + (https://sphinx-gallery.github.io/stable/configuration.html#auto-documenting-your-api-with-links-to-examples) + + For docs on autodoc-process-docstring, see the autodoc docs: + https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html + """ + + if what == "class": + lines.append(f".. minigallery:: {name}") + lines.append(f" :add-heading: Examples using ``{name.split('.')[-1]}``:") + # avoid heading entirely to avoid warning. As a bonud it actually renders better + lines.append(" :heading-level: 9") + lines.append("\n") + + +def setup(app): + app.connect('autodoc-process-docstring', inject_minigalleries); From 35c8e2deb67d430b6f3ff82ad018219e61df5b49 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 11:13:14 +0100 Subject: [PATCH 06/14] Avoid generating gallery on objects that aren't used in any example --- docs/source/conf.py | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 7b67b2dc33d..1658864213d 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -20,6 +20,10 @@ # import os # import sys # sys.path.insert(0, os.path.abspath('.')) + +from pathlib import Path +import os + import torch import torchvision import pytorch_sphinx_theme @@ -259,7 +263,10 @@ def handle_item(fieldarg, content): def inject_minigalleries(app, what, name, obj, options, lines): - """Inject minigallery into docstrings. + """Inject a minigallery into a docstring. + + This avoids having to manually write the .. minigallery directive for every item we want a minigallery for, + as it would be easy to miss some. This callback is called after the .. auto directives (like ..autoclass) have been processed, and modifies the lines parameter inplace to add the .. minigallery that will show which examples @@ -273,6 +280,15 @@ def inject_minigalleries(app, what, name, obj, options, lines): https://www.sphinx-doc.org/en/master/usage/extensions/autodoc.html """ + conf_file_path = Path(__file__).parent.absolute() + backrefs_path = conf_file_path / sphinx_gallery_conf['backreferences_dir'] / (name + '.examples') + if not (os.path.isfile(backrefs_path) and os.path.getsize(backrefs_path) > 0): + # We avoid showing the (empty) minigallery if there's nothing to show, i.e. if the object + # isn't used in any example. + # FIXME: this check can be removed once https://github.com/sphinx-gallery/sphinx-gallery/pull/813 + # is merged and the new sphinx-gallery version (> 0.8.x) is released. + return + if what == "class": lines.append(f".. minigallery:: {name}") lines.append(f" :add-heading: Examples using ``{name.split('.')[-1]}``:") From f1408f1dc16bf566b34d0294ac3942551bf297f0 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 11:18:58 +0100 Subject: [PATCH 07/14] Add backlinks to functions too --- docs/source/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index 1658864213d..c29d321f98f 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -289,7 +289,7 @@ def inject_minigalleries(app, what, name, obj, options, lines): # is merged and the new sphinx-gallery version (> 0.8.x) is released. return - if what == "class": + if what in ("class", "function"): lines.append(f".. minigallery:: {name}") lines.append(f" :add-heading: Examples using ``{name.split('.')[-1]}``:") # avoid heading entirely to avoid warning. As a bonud it actually renders better From 74d16f060b704de7f0d71d16192bacfa3e3a68b9 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 11:40:47 +0100 Subject: [PATCH 08/14] updates to Mkaefile --- docs/Makefile | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/Makefile b/docs/Makefile index 1cacf08002f..41cb4e1e45e 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -19,6 +19,15 @@ docset: html cp $(SPHINXPROJ).docset/icon.png $(SPHINXPROJ).docset/icon@2x.png convert $(SPHINXPROJ).docset/icon@2x.png -resize 16x16 $(SPHINXPROJ).docset/icon.png +html-noplot: # Avoids running the gallery examples, which may take time + $(SPHINXBUILD) -D plot_gallery=0 -b html $(ASPHINXOPTS) "$(SOURCEDIR)" "$(BUILDDIR)"/html + @echo + @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." + +clean: + rm -rf $(BUILDDIR)/* + rm -rf auto_examples/ + .PHONY: help Makefile docset # Catch-all target: route all unknown targets to Sphinx using the new From b8ceeec26fa2fee968b8a9fec4b372f554d67205 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 14:03:23 +0100 Subject: [PATCH 09/14] Better example --- docs/Makefile | 2 +- gallery/assets/astronaut.jpg | Bin 0 -> 40344 bytes gallery/plot_transforms.py | 79 +++++++++++++++++++++-------------- 3 files changed, 48 insertions(+), 33 deletions(-) create mode 100644 gallery/assets/astronaut.jpg diff --git a/docs/Makefile b/docs/Makefile index 41cb4e1e45e..58daa471f5c 100644 --- a/docs/Makefile +++ b/docs/Makefile @@ -20,7 +20,7 @@ docset: html convert $(SPHINXPROJ).docset/icon@2x.png -resize 16x16 $(SPHINXPROJ).docset/icon.png html-noplot: # Avoids running the gallery examples, which may take time - $(SPHINXBUILD) -D plot_gallery=0 -b html $(ASPHINXOPTS) "$(SOURCEDIR)" "$(BUILDDIR)"/html + $(SPHINXBUILD) -D plot_gallery=0 -b html $(ASPHINXOPTS) "$(BUILDDIR)"/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." diff --git a/gallery/assets/astronaut.jpg b/gallery/assets/astronaut.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9716f6562697103a3a5086ae98493eb8e5fbb46b GIT binary patch literal 40344 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 IsW3nP*~(Sxwg3PC literal 0 HcmV?d00001 diff --git a/gallery/plot_transforms.py b/gallery/plot_transforms.py index 05248242045..bf393072159 100644 --- a/gallery/plot_transforms.py +++ b/gallery/plot_transforms.py @@ -3,48 +3,63 @@ Illustration of transforms ========================== -This file illustrates how torchvision transforms work on some images. - -(Note: this is super WIP) +This example illustrates the various transforms available in :mod:`torchvision.transforms`. """ -#################################### -# Pad -# --- -# -# The :class:`~torchvision.transforms.Pad` transform is super cool - -# from PIL import Image -# import matplotlib.pyplot as plt -# plt.plot([1,2,3,4]) -from PIL import Image, ImageMath -from skimage.data import astronaut +from PIL import Image +from pathlib import Path import matplotlib.pyplot as plt import numpy as np -from torchvision.transforms import Pad -img = Image.fromarray(astronaut()) +import torchvision.transforms as tf + + +orig_img = Image.open(Path('assets') / 'astronaut.jpg') + + +def plot(img, title="", with_orig=True, **kwargs): + def _plot(img, title, **kwargs): + plt.figure().suptitle("Original image", fontsize=25) + plt.imshow(np.asarray(img), **kwargs) + plt.axis('off') + + if with_orig: + _plot(orig_img, "Original image") + _plot(img, title, **kwargs) -plt.figure().suptitle("Before padding") -plt.imshow(np.asarray(img)) -padded_img = Pad(padding=30)(img) -plt.figure().suptitle("After padding") -plt.imshow(np.asarray(padded_img)) + +#################################### +# Pad +# --- +# The :class:`~torchvision.transforms.Pad` transform +# (see also :func:`~torchvision.transforms.functional.pad`) +# fills image borders with some pixel values. +padded_img = tf.Pad(padding=30)(orig_img) +plot(padded_img, "Padded image") #################################### # Resize # ------ -# -# The :class:`~torchvision.transforms.Resize` transform is even cooler - -from torchvision.transforms import Resize -plt.figure().suptitle("Before resize") -plt.imshow(np.asarray(img)) - -padded_img = Resize(size=30)(img) -plt.figure().suptitle("After resize") -plt.imshow(np.asarray(padded_img)) +# The :class:`~torchvision.transforms.Resize` transform +# (see also :func:`~torchvision.transforms.functional.resize`) +# resizes an image. +resized_img = tf.Resize(size=30)(orig_img) +plot(resized_img, "Resized image") +#################################### +# ColorJitter +# ----------- +# The :class:`~torchvision.transforms.ColorJitter` transform +# randomly changes the brightness, saturation, and other properties of an image. +jitted_img = tf.ColorJitter(brightness=.5, hue=.3)(orig_img) +plot(jitted_img, "Jitted image") -print(np.exp(3)) \ No newline at end of file +#################################### +# Grayscale +# --------- +# The :class:`~torchvision.transforms.Grayscale` transform +# (see also :func:`~torchvision.transforms.functional.to_grayscale`) +# converts an image to grayscale +gray_img = tf.Grayscale()(orig_img) +plot(gray_img, "Grayscale image", cmap='gray') From dd1ebb51dee7ddd382b77558fb76e996aed02694 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 14:20:18 +0100 Subject: [PATCH 10/14] flake8 --- docs/source/conf.py | 10 +++++----- gallery/plot_transforms.py | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/docs/source/conf.py b/docs/source/conf.py index c29d321f98f..60994eae8b9 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -52,10 +52,10 @@ ] sphinx_gallery_conf = { - 'examples_dirs': '../../gallery/', # path to your example scripts - 'gallery_dirs': 'auto_examples', # path to where to save gallery generated output - 'backreferences_dir': 'gen_modules/backreferences', - 'doc_module' : ('torchvision',), + 'examples_dirs': '../../gallery/', # path to your example scripts + 'gallery_dirs': 'auto_examples', # path to where to save gallery generated output + 'backreferences_dir': 'gen_modules/backreferences', + 'doc_module': ('torchvision',), } napoleon_use_ivar = True @@ -298,4 +298,4 @@ def inject_minigalleries(app, what, name, obj, options, lines): def setup(app): - app.connect('autodoc-process-docstring', inject_minigalleries); + app.connect('autodoc-process-docstring', inject_minigalleries) diff --git a/gallery/plot_transforms.py b/gallery/plot_transforms.py index bf393072159..efb5878798d 100644 --- a/gallery/plot_transforms.py +++ b/gallery/plot_transforms.py @@ -28,7 +28,6 @@ def _plot(img, title, **kwargs): _plot(img, title, **kwargs) - #################################### # Pad # --- @@ -39,7 +38,7 @@ def _plot(img, title, **kwargs): plot(padded_img, "Padded image") #################################### -# Resize +# Resize # ------ # The :class:`~torchvision.transforms.Resize` transform # (see also :func:`~torchvision.transforms.functional.resize`) From 967c5346ad7c892645119b392c963516f27f51cc Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 14:21:12 +0100 Subject: [PATCH 11/14] update requirements.txt --- docs/requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index 1d43475cabd..e87cc0ec10c 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,6 +1,5 @@ sphinx sphinx-gallery -scikit-image matplotlib numpy -e git+git://github.com/pytorch/pytorch_sphinx_theme.git#egg=pytorch_sphinx_theme From 339cb9b0747a5b2df336855cae13304f340c4df2 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 14:31:59 +0100 Subject: [PATCH 12/14] title fix --- gallery/plot_transforms.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gallery/plot_transforms.py b/gallery/plot_transforms.py index efb5878798d..9c8e60f6ca8 100644 --- a/gallery/plot_transforms.py +++ b/gallery/plot_transforms.py @@ -19,7 +19,7 @@ def plot(img, title="", with_orig=True, **kwargs): def _plot(img, title, **kwargs): - plt.figure().suptitle("Original image", fontsize=25) + plt.figure().suptitle(title, fontsize=25) plt.imshow(np.asarray(img), **kwargs) plt.axis('off') From 0963f146cd68dcd21cdc72d7be53786420a353f5 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Fri, 16 Apr 2021 14:49:35 +0100 Subject: [PATCH 13/14] tf -> T --- gallery/plot_transforms.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/gallery/plot_transforms.py b/gallery/plot_transforms.py index 9c8e60f6ca8..44f4f872fd3 100644 --- a/gallery/plot_transforms.py +++ b/gallery/plot_transforms.py @@ -11,7 +11,7 @@ import matplotlib.pyplot as plt import numpy as np -import torchvision.transforms as tf +import torchvision.transforms as T orig_img = Image.open(Path('assets') / 'astronaut.jpg') @@ -34,7 +34,7 @@ def _plot(img, title, **kwargs): # The :class:`~torchvision.transforms.Pad` transform # (see also :func:`~torchvision.transforms.functional.pad`) # fills image borders with some pixel values. -padded_img = tf.Pad(padding=30)(orig_img) +padded_img = T.Pad(padding=30)(orig_img) plot(padded_img, "Padded image") #################################### @@ -43,7 +43,7 @@ def _plot(img, title, **kwargs): # The :class:`~torchvision.transforms.Resize` transform # (see also :func:`~torchvision.transforms.functional.resize`) # resizes an image. -resized_img = tf.Resize(size=30)(orig_img) +resized_img = T.Resize(size=30)(orig_img) plot(resized_img, "Resized image") #################################### @@ -51,7 +51,7 @@ def _plot(img, title, **kwargs): # ----------- # The :class:`~torchvision.transforms.ColorJitter` transform # randomly changes the brightness, saturation, and other properties of an image. -jitted_img = tf.ColorJitter(brightness=.5, hue=.3)(orig_img) +jitted_img = T.ColorJitter(brightness=.5, hue=.3)(orig_img) plot(jitted_img, "Jitted image") #################################### @@ -60,5 +60,5 @@ def _plot(img, title, **kwargs): # The :class:`~torchvision.transforms.Grayscale` transform # (see also :func:`~torchvision.transforms.functional.to_grayscale`) # converts an image to grayscale -gray_img = tf.Grayscale()(orig_img) +gray_img = T.Grayscale()(orig_img) plot(gray_img, "Grayscale image", cmap='gray') From 053224eb05043fc190a3f4fdd08afa3e469c7410 Mon Sep 17 00:00:00 2001 From: Nicolas Hug Date: Mon, 19 Apr 2021 11:09:23 +0100 Subject: [PATCH 14/14] set sphinx version to 2.4.4 --- docs/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/requirements.txt b/docs/requirements.txt index e87cc0ec10c..6fda04707ea 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,4 @@ -sphinx +sphinx==2.4.4 sphinx-gallery matplotlib numpy