---
title: 'Interactive Notebooks (Jupyter, Colab, Kaggle)'
description: >-
  Audience: Users looking to train models in interactive notebooks (Jupyter,
  Colab, Kaggle, etc.).
canonical: 'https://lightning.ai/docs/pytorch/stable/reference/common/notebooks'
---
# Interactive Notebooks (Jupyter, Colab, Kaggle) {#interactive-notebooks-jupyter-colab-kaggle}

**Audience:** Users looking to train models in interactive notebooks (Jupyter, Colab, Kaggle, etc.).

## Lightning in notebooks {#lightning-in-notebooks}

You can use the Lightning Trainer in interactive notebooks just like in a regular Python script, including multi-GPU training!

```python
import lightning as L

# Works in Jupyter, Colab and Kaggle!
trainer = L.Trainer(accelerator="auto", devices="auto")
```

You can find many notebook examples on our [tutorials page](/docs/pytorch/2.6.6/more/tutorials.md) too!

## Full example {#full-example}

Paste the following code block into a notebook cell:

```python
import lightning as L
from torch import nn, optim, utils
import torchvision

encoder = nn.Sequential(nn.Linear(28 * 28, 64), nn.ReLU(), nn.Linear(64, 3))
decoder = nn.Sequential(nn.Linear(3, 64), nn.ReLU(), nn.Linear(64, 28 * 28))

class LitAutoEncoder(L.LightningModule):
    def __init__(self, encoder, decoder):
        super().__init__()
        self.encoder = encoder
        self.decoder = decoder

    def training_step(self, batch, batch_idx):
        x, _ = batch
        x = x.view(x.size(0), -1)
        z = self.encoder(x)
        x_hat = self.decoder(z)
        loss = nn.functional.mse_loss(x_hat, x)
        self.log("train_loss", loss)
        return loss

    def configure_optimizers(self):
        return optim.Adam(self.parameters(), lr=1e-3)

    def prepare_data(self):
        torchvision.datasets.MNIST(".", download=True)

    def train_dataloader(self):
        dataset = torchvision.datasets.MNIST(".", transform=torchvision.transforms.ToTensor())
        return utils.data.DataLoader(dataset, batch_size=64)

autoencoder = LitAutoEncoder(encoder, decoder)
trainer = L.Trainer(max_epochs=2, devices="auto")
trainer.fit(model=autoencoder)
```

## Multi-GPU Limitations {#multi-gpu-limitations}

The multi-GPU capabilities in Jupyter are enabled by launching processes using the 'fork' start method.
It is the only supported way of multi-processing in notebooks, but also brings some limitations that you should be aware of.

### Avoid initializing CUDA before .fit() {#avoid-initializing-cuda-before-fit}

Don't run torch CUDA functions before calling `trainer.fit()` in any of the notebook cells beforehand, otherwise your code may hang or crash.

```python
# BAD: Don't run CUDA-related code before `.fit()`
x = torch.tensor(1).cuda()
torch.cuda.empty_cache()
torch.cuda.is_available()

trainer = L.Trainer(accelerator="cuda", devices=2)
trainer.fit(model)
```

### Move data loading code inside the hooks {#move-data-loading-code-inside-the-hooks}

If you define/load your data in the main process before calling `trainer.fit()`, you may see a slowdown or crashes (segmentation fault, SIGSEV, etc.).

```python
# BAD: Don't load data in the main process
dataset = MyDataset("data/")
train_dataloader = torch.utils.data.DataLoader(dataset)

trainer = L.Trainer(accelerator="cuda", devices=2)
trainer.fit(model, train_dataloader)
```

The best practice is to move your data loading code inside the `*_dataloader()` hooks in the `LightningModule` or `LightningDataModule` as shown in the [example above](/docs/pytorch/2.6.6/reference/common/notebooks.md).

---

**Navigation**

- Parent: [Common](/docs/pytorch/2.6.6/reference/common.md)
