Skip to content

Commit

Permalink
doc updates (#530)
Browse files Browse the repository at this point in the history
* doc updates

* Apply suggestions from code review

* fix

Co-authored-by: Jirka Borovec <Borda@users.noreply.github.com>
Co-authored-by: Jirka Borovec <jirka.borovec@seznam.cz>
  • Loading branch information
3 people authored Jan 20, 2021
1 parent f0cc60b commit 96b8c37
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 58 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ train_data = DataLoader(MyDataset(transforms=SimCLRTrainDataTransform(input_heig
val_data = DataLoader(MyDataset(transforms=SimCLREvalDataTransform(input_height=32)))

# model
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/simclr-cifar10-v1-exp12_87_52/epoch%3D960.ckpt'
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)

simclr.freeze()
Expand Down
2 changes: 1 addition & 1 deletion docs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

# You can set these variables from the command line.
SPHINXOPTS = -W
SPHINXBUILD = sphinx-build
SPHINXBUILD = python $(shell which sphinx-build)
SOURCEDIR = source
BUILDDIR = build

Expand Down
16 changes: 9 additions & 7 deletions docs/source/introduction_guide.rst
Original file line number Diff line number Diff line change
Expand Up @@ -145,20 +145,22 @@ don't have enough data, time or money to do your own training.

For example, you could use a pretrained VAE to generate features for an image dataset.

.. code-block:: python
.. testcode::

from pl_bolts.models.autoencoders import VAE
from pl_bolts.models.self_supervised import CPCV2

model1 = VAE(pretrained='imagenet2012')
model1 = VAE(input_height=32, pretrained='imagenet2012')
encoder = model1.encoder
encoder.freeze()
encoder.eval()

# bolts are pretrained on different datasets
model2 = CPCV2(encoder='resnet18', pretrained='imagenet128').freeze()
model3 = CPCV2(encoder='resnet18', pretrained='stl10').freeze()

for (x, y) in own_data
.. code-block:: python
for (x, y) in own_data:
features = encoder(x)
feat2 = model2(x)
feat3 = model3(x)
Expand All @@ -179,7 +181,7 @@ you can use any finetuning protocol you prefer.
resnet18 = model.encoder
# don't call .freeze()
classifier = LogisticRegression()
classifier = LogisticRegression(...)
for (x, y) in own_data:
feats = resnet18(x)
Expand All @@ -192,9 +194,9 @@ you can use any finetuning protocol you prefer.
# FREEZE!
model = CPCV2(encoder='resnet18', pretrained='imagenet128')
resnet18 = model.encoder
resnet18.freeze()
resnet18.eval()
classifier = LogisticRegression()
classifier = LogisticRegression(...)
for epoch in epochs:
for (x, y) in own_data:
Expand Down
107 changes: 68 additions & 39 deletions docs/source/models_howto.rst
Original file line number Diff line number Diff line change
Expand Up @@ -13,46 +13,57 @@ don't have enough data, time or money to do your own training.

For example, you could use a pretrained VAE to generate features for an image dataset.

.. code-block:: python
.. testcode::

from pl_bolts.models.autoencoders import VAE
from pl_bolts.models.self_supervised import SimCLR

model = VAE(pretrained='imagenet2012')
encoder = model.encoder
encoder.freeze()
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)
encoder = simclr.encoder
encoder.eval()

.. code-block:: python
for (x, y) in own_data
for (x, y) in own_data:
features = encoder(x)
The advantage of bolts is that each system can be decomposed and used in interesting ways.
For instance, this resnet18 was trained using self-supervised learning (no labels) on Imagenet, and thus
might perform better than the same resnet18 trained with labels
For instance, this resnet50 was trained using self-supervised learning (no labels) on Imagenet, and thus
might perform better than the same resnet50 trained with labels

.. code-block:: python
.. testcode::

# trained without labels
from pl_bolts.models.self_supervised import CPCV2
from pl_bolts.models.self_supervised import SimCLR

model = CPCV2(encoder='resnet18', pretrained='imagenet128')
resnet18_unsupervised = model.encoder.freeze()
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)
resnet50_unsupervised = simclr.encoder.eval()

# trained with labels
from torchvision.models import resnet18
resnet18_supervised = resnet18(pretrained=True)
from torchvision.models import resnet50
resnet50_supervised = resnet50(pretrained=True)

.. code-block:: python
# perhaps the features when trained without labels are much better for classification or other tasks
x = image_sample()
unsup_feats = resnet18_unsupervised(x)
sup_feats = resnet18_supervised(x)
unsup_feats = resnet50_unsupervised(x)
sup_feats = resnet50_supervised(x)
# which one will be better?
Bolts are often trained on more than just one dataset.

.. code-block:: python
.. testcode::

from pl_bolts.models.self_supervised import SimCLR

model = CPCV2(encoder='resnet18', pretrained='stl10')
# imagenet weights
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)

simclr.freeze()

---------------

Expand All @@ -66,16 +77,21 @@ Unfrozen Finetuning
^^^^^^^^^^^^^^^^^^^
In this approach, we load the pretrained model and unfreeze from the beginning

.. code-block:: python
.. testcode::

from pl_bolts.models.self_supervised import SimCLR

model = CPCV2(encoder='resnet18', pretrained='imagenet128')
resnet18 = model.encoder
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)
resnet50 = simclr.encoder
# don't call .freeze()

classifier = LogisticRegression()
.. code-block:: python
classifier = LogisticRegression(...)
for (x, y) in own_data:
feats = resnet18(x)
feats = resnet50(x)
y_hat = classifier(feats)
...
Expand All @@ -87,7 +103,7 @@ Or as a LightningModule
def __init__(self, encoder):
self.encoder = encoder
self.classifier = LogisticRegression()
self.classifier = LogisticRegression(...)
def training_step(self, batch, batch_idx):
(x, y) = batch
Expand All @@ -97,7 +113,7 @@ Or as a LightningModule
return loss
trainer = Trainer(gpus=2)
model = FineTuner(resnet18)
model = FineTuner(resnet50)
trainer.fit(model)
Sometimes this works well, but more often it's better to keep the encoder frozen for a while
Expand All @@ -106,24 +122,29 @@ Freeze then unfreeze
^^^^^^^^^^^^^^^^^^^^
The approach that works best most often is to freeze first then unfreeze later

.. code-block:: python
.. testcode::

# freeze!
model = CPCV2(encoder='resnet18', pretrained='imagenet128')
resnet18 = model.encoder
resnet18.freeze()
from pl_bolts.models.self_supervised import SimCLR

classifier = LogisticRegression()
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)
resnet50 = simclr.encoder
resnet50.eval()

.. code-block:: python
classifier = LogisticRegression(...)
for epoch in epochs:
for (x, y) in own_data:
feats = resnet18(x)
feats = resnet50(x)
y_hat = classifier(feats)
loss = cross_entropy_with_logits(y_hat, y)
# unfreeze after 10 epochs
if epoch == 10:
resnet18.unfreeze()
resnet50.unfreeze()
.. note:: In practice, unfreezing later works MUCH better.

Expand All @@ -138,7 +159,7 @@ Or in Lightning as a Callback so you don't pollute your research code.
encoder.unfreeze()
trainer = Trainer(gpus=2, callbacks=[UnFreezeCallback()])
model = FineTuner(resnet18)
model = FineTuner(resnet50)
trainer.fit(model)
Unless you still need to mix it into your research code.
Expand All @@ -149,7 +170,7 @@ Unless you still need to mix it into your research code.
def __init__(self, encoder):
self.encoder = encoder
self.classifier = LogisticRegression()
self.classifier = LogisticRegression(...)
def training_step(self, batch, batch_idx):
Expand All @@ -176,12 +197,14 @@ to get the most value out of your data.

.. code-block:: python
from pl_bolts.models.autoencoders import VAE
learning_rates = [0.01, 0.001, 0.0001]
hidden_dim = [128, 256, 512]
for lr in learning_rates:
for hd in hidden_dim:
vae = VAE(hidden_dim=hd, learning_rate=lr)
vae = VAE(input_height=32, hidden_dim=hd, learning_rate=lr)
trainer = Trainer()
trainer.fit(vae)
Expand Down Expand Up @@ -258,7 +281,7 @@ figure out if your VAE implementation was correct, or if your training loop was

**Example 2: Changing the generator step of a GAN**

.. code-block:: python
.. testcode::

from pl_bolts.models.gans import GAN

Expand Down Expand Up @@ -287,7 +310,7 @@ figure out if your VAE implementation was correct, or if your training loop was

**Example 3: Changing the way the loss is calculated in a contrastive self-supervised learning approach**

.. code-block:: python
.. testcode::

from pl_bolts.models.self_supervised import AMDIM

Expand Down Expand Up @@ -333,22 +356,28 @@ approaches.
**Example 2: Use the contrastive task of AMDIM in CPC**

.. code-block:: python
.. testcode::

from pl_bolts.models.self_supervised import AMDIM, CPCV2

default_amdim_task = AMDIM().contrastive_task
model = CPCV2(contrastive_task=default_amdim_task, encoder='cpc_default')
# you might need to modify the cpc encoder depending on what you use

.. testoutput::
:hide:
:options: +ELLIPSIS, +NORMALIZE_WHITESPACE

...

---------------

Compose new ideas
^^^^^^^^^^^^^^^^^
You may also be interested in creating completely new approaches that mix and match all sorts of different
pieces together

.. code-block:: python
.. testcode::

# this model is for illustration purposes, it makes no research sense but it's intended to show
# that you can be as creative and expressive as you want.
Expand Down
19 changes: 9 additions & 10 deletions docs/source/self_supervised_models.rst
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,16 @@ The models in this module are trained unsupervised and thus can capture better i

In this example, we'll load a resnet 18 which was pretrained on imagenet using CPC as the pretext task.

Example::
.. testcode::

from pl_bolts.models.self_supervised import CPCV2
from pl_bolts.models.self_supervised import SimCLR

# load resnet18 pretrained using CPC on imagenet
model = CPCV2(pretrained='resnet18')
cpc_resnet18 = model.encoder
cpc_resnet18.freeze()
# load resnet50 pretrained using SimCLR on imagenet
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)

# it supports any torchvision resnet
model = CPCV2(pretrained='resnet50')
simclr_resnet50 = simclr.encoder
simclr_resnet50.eval()

This means you can now extract image representations that were pretrained via unsupervised learning.

Expand All @@ -38,7 +37,7 @@ Example::
my_dataset = SomeDataset()
for batch in my_dataset:
x, y = batch
out = cpc_resnet18(x)
out = simclr_resnet50(x)

----------------

Expand Down Expand Up @@ -325,7 +324,7 @@ CIFAR-10 pretrained model::

from pl_bolts.models.self_supervised import SimCLR

weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/simclr-cifar10-v1-exp12_87_52/epoch%3D960.ckpt'
weight_path = 'https://pl-bolts-weights.s3.us-east-2.amazonaws.com/simclr/bolts_simclr_imagenet/simclr_imagenet.ckpt'
simclr = SimCLR.load_from_checkpoint(weight_path, strict=False)

simclr.freeze()
Expand Down

0 comments on commit 96b8c37

Please sign in to comment.