Skip to content

Commit 0f10df0

Browse files
authored
docs: Added RST files for notebooks (#101)
1 parent 8e91898 commit 0f10df0

File tree

3 files changed

+327
-1
lines changed

3 files changed

+327
-1
lines changed

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@
6161
# List of patterns, relative to source directory, that match files and
6262
# directories to ignore when looking for source files.
6363
# This pattern also affects html_static_path and html_extra_path.
64-
exclude_patterns = []
64+
exclude_patterns = ['notebooks/*.rst']
6565

6666

6767
# The name of the Pygments (syntax highlighting) style to use.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
Installation
2+
============
3+
4+
In this tutorial, you will need the entire project codebase. So first,
5+
we clone the project’s GitHub repository and install from source.
6+
7+
.. code-block::python
8+
9+
>>> !git clone https://github.com/frgfm/torch-cam.git
10+
>>> !pip install -e torch-cam/.
11+
12+
13+
Hardware information
14+
====================
15+
16+
GPU information
17+
---------------
18+
19+
To be able to run the benchmark on GPU, you need to have the correct
20+
driver and CUDA installation. If you get a message starting with: >
21+
NVIDIA-SMI has failed…
22+
23+
The script will be running on CPU as PyTorch isn’t able to access any
24+
CUDA-capable device.
25+
26+
.. code-block::python
27+
28+
>>> !nvidia-smi
29+
NVIDIA-SMI has failed because it couldn't communicate with the NVIDIA driver. Make sure that the latest NVIDIA driver is installed and running.
30+
31+
32+
CPU information
33+
---------------
34+
35+
Latency will vary greatly depending on the capabilities of your CPU.
36+
Some models are optimized for CPU architectures (MobileNet V3 for
37+
instance), while others were only designed for GPU and will thus yield
38+
poor latency when run on CPU.
39+
40+
.. code-block::python
41+
42+
>>> !lscpu
43+
Architecture: x86_64
44+
CPU op-mode(s): 32-bit, 64-bit
45+
Byte Order: Little Endian
46+
CPU(s): 2
47+
On-line CPU(s) list: 0,1
48+
Thread(s) per core: 2
49+
Core(s) per socket: 1
50+
Socket(s): 1
51+
NUMA node(s): 1
52+
Vendor ID: AuthenticAMD
53+
CPU family: 23
54+
Model: 49
55+
Model name: AMD EPYC 7B12
56+
Stepping: 0
57+
CPU MHz: 2249.998
58+
BogoMIPS: 4499.99
59+
Hypervisor vendor: KVM
60+
Virtualization type: full
61+
L1d cache: 32K
62+
L1i cache: 32K
63+
L2 cache: 512K
64+
L3 cache: 16384K
65+
NUMA node0 CPU(s): 0,1
66+
Flags: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ht syscall nx mmxext fxsr_opt pdpe1gb rdtscp lm constant_tsc rep_good nopl nonstop_tsc cpuid extd_apicid tsc_known_freq pni pclmulqdq ssse3 fma cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx f16c rdrand hypervisor lahf_lm cmp_legacy cr8_legacy abm sse4a misalignsse 3dnowprefetch osvw topoext ssbd ibrs ibpb stibp vmmcall fsgsbase tsc_adjust bmi1 avx2 smep bmi2 rdseed adx smap clflushopt clwb sha_ni xsaveopt xsavec xgetbv1 clzero xsaveerptr arat npt nrip_save umip rdpid
67+
68+
69+
Usage
70+
=====
71+
72+
The latency evaluation script provides several options for you to play
73+
with: change the input size, the architecture or the CAM method to
74+
better reflect your use case.
75+
76+
.. code-block::python
77+
78+
>>> !cd torch-cam/ && python scripts/eval_latency.py --help
79+
usage: eval_latency.py [-h] [--arch ARCH] [--size SIZE]
80+
[--class-idx CLASS_IDX] [--device DEVICE] [--it IT]
81+
method
82+
83+
CAM method latency benchmark
84+
85+
positional arguments:
86+
method CAM method to use
87+
88+
optional arguments:
89+
-h, --help show this help message and exit
90+
--arch ARCH Name of the torchvision architecture (default:
91+
resnet18)
92+
--size SIZE The image input size (default: 224)
93+
--class-idx CLASS_IDX
94+
Index of the class to inspect (default: 232)
95+
--device DEVICE Default device to perform computation on (default:
96+
None)
97+
--it IT Number of iterations to run (default: 100)
98+
99+
100+
Architecture designed for GPU
101+
-----------------------------
102+
103+
Let’s benchmark the latency of CAM methods with the popular ResNet
104+
architecture
105+
106+
.. code-block::python
107+
108+
>>> !cd torch-cam/ && python scripts/eval_latency.py SmoothGradCAMpp --arch resnet18
109+
Downloading: "https://download.pytorch.org/models/resnet18-f37072fd.pth" to /root/.cache/torch/hub/checkpoints/resnet18-f37072fd.pth
110+
100% 44.7M/44.7M [00:00<00:00, 85.9MB/s]
111+
/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)
112+
return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
113+
WARNING:root:no value was provided for `target_layer`, thus set to 'layer4'.
114+
SmoothGradCAMpp w/ resnet18 (100 runs on (224, 224) inputs)
115+
mean 1143.17ms, std 36.79ms
116+
117+
118+
.. code-block::python
119+
120+
>>> !cd torch-cam/ && python scripts/eval_latency.py LayerCAM --arch resnet18
121+
/usr/local/lib/python3.7/dist-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)
122+
return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
123+
WARNING:root:no value was provided for `target_layer`, thus set to 'layer4'.
124+
LayerCAM w/ resnet18 (100 runs on (224, 224) inputs)
125+
mean 189.64ms, std 8.82ms
126+
127+
128+
Architecture designed for CPU
129+
-----------------------------
130+
131+
As mentioned, we’ll consider MobileNet V3 here.
132+
133+
.. code-block::python
134+
135+
>>> !cd torch-cam/ && python scripts/eval_latency.py SmoothGradCAMpp --arch mobilenet_v3_large
136+
Downloading: "https://download.pytorch.org/models/mobilenet_v3_large-8738ca79.pth" to /root/.cache/torch/hub/checkpoints/mobilenet_v3_large-8738ca79.pth
137+
100% 21.1M/21.1M [00:00<00:00, 71.5MB/s]
138+
WARNING:root:no value was provided for `target_layer`, thus set to 'features.4.block.1'.
139+
SmoothGradCAMpp w/ mobilenet_v3_large (100 runs on (224, 224) inputs)
140+
mean 762.18ms, std 26.95ms
141+
142+
143+
.. code-block::python
144+
145+
>>> !cd torch-cam/ && python scripts/eval_latency.py LayerCAM --arch mobilenet_v3_large
146+
WARNING:root:no value was provided for `target_layer`, thus set to 'features.4.block.1'.
147+
LayerCAM w/ mobilenet_v3_large (100 runs on (224, 224) inputs)
148+
mean 148.76ms, std 7.86ms
149+

docs/source/notebooks/quicktour.rst

Lines changed: 177 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,177 @@
1+
Installation
2+
============
3+
4+
Install all the dependencies to make the most out of TorchCAM
5+
6+
.. code-block::python
7+
8+
>>> !pip install torchvision matplotlib
9+
10+
11+
Latest stable release
12+
---------------------
13+
14+
.. code-block:: python
15+
16+
>>> !pip install torch-cam
17+
18+
From source
19+
-----------
20+
21+
.. code-block:: python
22+
23+
>>> # Install the most up-to-date version from GitHub
24+
>>> !pip install -e git+https://github.com/frgfm/torch-cam.git#egg=torchcam
25+
26+
27+
Now go to ``Runtime/Restart runtime`` for your changes to take effect!
28+
29+
Basic usage
30+
===========
31+
32+
.. code-block:: python
33+
34+
>>> # Download an image
35+
>>> !wget https://www.woopets.fr/assets/races/000/066/big-portrait/border-collie.jpg
36+
>>> # Set this to your image path if you wish to run it on your own data
37+
>>> img_path = "border-collie.jpg"
38+
39+
40+
.. code-block:: python
41+
42+
>>> # Instantiate your model here
43+
>>> from torchvision.models import resnet18
44+
>>> model = resnet18(pretrained=True).eval()
45+
46+
47+
48+
Illustrate your classifier capabilities
49+
---------------------------------------
50+
51+
.. code-block:: python
52+
53+
>>> %matplotlib inline
54+
>>> # All imports
55+
>>> from torchvision.io.image import read_image
56+
>>> from torchvision.transforms.functional import normalize, resize, to_pil_image
57+
>>> import matplotlib.pyplot as plt
58+
>>> from torchcam.cams import SmoothGradCAMpp, LayerCAM
59+
>>> from torchcam.utils import overlay_mask
60+
61+
.. code-block:: python
62+
63+
>>> cam_extractor = SmoothGradCAMpp(model)
64+
>>> # Get your input
65+
>>> img = read_image(img_path)
66+
>>> # Preprocess it for your chosen model
67+
>>> input_tensor = normalize(resize(img, (224, 224)) / 255., [0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
68+
>>> # Preprocess your data and feed it to the model
69+
>>> out = model(input_tensor.unsqueeze(0))
70+
>>> # Retrieve the CAM by passing the class index and the model output
71+
>>> cams = cam_extractor(out.squeeze(0).argmax().item(), out)
72+
73+
.. code-block:: python
74+
75+
>>> # Notice that there is one CAM per target layer (here only 1)
76+
>>> for cam in cams:
77+
>>> print(cam.shape)
78+
torch.Size([7, 7])
79+
80+
81+
.. code-block:: python
82+
83+
>>> # The raw CAM
84+
>>> for name, cam in zip(cam_extractor.target_names, cams):
85+
>>> plt.imshow(cam.numpy()); plt.axis('off'); plt.title(name); plt.show()
86+
87+
88+
.. code-block:: python
89+
90+
>>> # Overlayed on the image
91+
>>> for name, cam in zip(cam_extractor.target_names, cams):
92+
>>> result = overlay_mask(to_pil_image(img), to_pil_image(cam, mode='F'), alpha=0.5)
93+
>>> plt.imshow(result); plt.axis('off'); plt.title(name); plt.show()
94+
95+
96+
.. code-block:: python
97+
98+
>>> # Once you're finished, clear the hooks on your model
99+
>>> cam_extractor.clear_hooks()
100+
101+
Advanced tricks
102+
===============
103+
104+
Extract localization cues
105+
-------------------------
106+
107+
.. code-block::python
108+
109+
>>> import torch
110+
>>> from torch.nn.functional import softmax, interpolate
111+
112+
.. code-block::python
113+
114+
>>> # Retrieve the CAM from several layers at the same time
115+
>>> cam_extractor = LayerCAM(model)
116+
>>> # Preprocess your data and feed it to the model
117+
>>> out = model(input_tensor.unsqueeze(0))
118+
>>> print(softmax(out, dim=1).max())
119+
tensor(0.9115, grad_fn=<MaxBackward1>)
120+
121+
122+
.. code-block::python
123+
124+
>>> cams = cam_extractor(out.squeeze(0).argmax().item(), out)
125+
126+
.. code-block::python
127+
128+
>>> # Resize it
129+
>>> resized_cams = [resize(to_pil_image(cam), img.shape[-2:]) for cam in cams]
130+
>>> segmaps = [to_pil_image((resize(cam.unsqueeze(0), img.shape[-2:]).squeeze(0) >= 0.5).to(dtype=torch.float32)) for cam in cams]
131+
>>> # Plot it
132+
>>> for name, cam, seg in zip(cam_extractor.target_names, resized_cams, segmaps):
133+
>>> _, axes = plt.subplots(1, 2)
134+
>>> axes[0].imshow(cam); axes[0].axis('off'); axes[0].set_title(name)
135+
>>> axes[1].imshow(seg); axes[1].axis('off'); axes[1].set_title(name)
136+
>>> plt.show()
137+
138+
139+
Fuse CAMs from multiple layers
140+
------------------------------
141+
142+
.. code-block::python
143+
144+
>>> # Retrieve the CAM from several layers at the same time
145+
>>> cam_extractor = LayerCAM(model, ["layer2", "layer3", "layer4"])
146+
>>> # Preprocess your data and feed it to the model
147+
>>> out = model(input_tensor.unsqueeze(0))
148+
>>> # Retrieve the CAM by passing the class index and the model output
149+
>>> cams = cam_extractor(out.squeeze(0).argmax().item(), out)
150+
151+
.. code-block::python
152+
153+
>>> # This time, there are several CAMs
154+
>>> for cam in cams:
155+
>>> print(cam.shape)
156+
torch.Size([14, 14])
157+
torch.Size([7, 7])
158+
159+
160+
.. code-block::python
161+
162+
>>> # The raw CAM
163+
>>> _, axes = plt.subplots(1, len(cam_extractor.target_names))
164+
>>> for idx, name, cam in zip(range(len(cam_extractor.target_names)), cam_extractor.target_names, cams):
165+
>>> axes[idx].imshow(cam.numpy()); axes[idx].axis('off'); axes[idx].set_title(name);
166+
>>> plt.show()
167+
168+
169+
.. code-block::python
170+
171+
>>> # Let's fuse them
172+
>>> fused_cam = cam_extractor.fuse_cams(cams)
173+
>>> # Plot the raw version
174+
>>> plt.imshow(fused_cam.numpy()); plt.axis('off'); plt.title(" + ".join(cam_extractor.target_names)); plt.show()
175+
>>> # Plot the overlayed version
176+
>>> result = overlay_mask(to_pil_image(img), to_pil_image(fused_cam, mode='F'), alpha=0.5)
177+
>>> plt.imshow(result); plt.axis('off'); plt.title(" + ".join(cam_extractor.target_names)); plt.show()

0 commit comments

Comments
 (0)