Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

doc updates #530

Merged
merged 16 commits into from
Jan 20, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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