Lesson Video:


This article is also a Jupyter Notebook available to be run from the top down. There will be code snippets that you can then run in any environment.

Below are the versions of fastai, fastcore, and wwf currently running at the time of writing this:

  • fastai: 2.1.10
  • fastcore: 1.3.13
  • wwf: 0.0.7

In this notebook we'll be looking at dblock.summary and how to interpret it

Libraries for today:

from fastai.vision.all import *

Below you will find the exact imports for everything we use today

from fastcore.transform import Pipeline

from fastai.data.block import CategoryBlock, DataBlock
from fastai.data.core import Datasets
from fastai.data.external import untar_data, URLs
from fastai.data.transforms import Categorize, GrandparentSplitter, IntToFloatTensor, Normalize, RandomSplitter, ToTensor, parent_label

from fastai.torch_core import to_device

from fastai.vision.augment import aug_transforms, Resize, RandomResizedCrop, FlipItem
from fastai.vision.data import ImageBlock, PILImage, get_image_files, imagenet_stats

Getting the Dataset

We'll use ImageWoof like we did in previous notebooks

path = untar_data(URLs.IMAGEWOOF)

And create our label dictionary similarly

lbl_dict = dict(
  n02086240= 'Shih-Tzu',
  n02087394= 'Rhodesian ridgeback',
  n02088364= 'Beagle',
  n02089973= 'English foxhound',
  n02093754= 'Australian terrier',
  n02096294= 'Border terrier',
  n02099601= 'Golden retriever',
  n02105641= 'Old English sheepdog',
  n02111889= 'Samoyed',
  n02115641= 'Dingo'
)

Some minimal transforms to get us by

item_tfms = Resize(128)
batch_tfms = [*aug_transforms(size=224, max_warp=0), Normalize.from_stats(*imagenet_stats)]
bs=64

And our DataBlock

pets = DataBlock(blocks=(ImageBlock, CategoryBlock),
                 get_items=get_image_files,
                 splitter=RandomSplitter(),
                 get_y=Pipeline([parent_label, lbl_dict.__getitem__]),
                 item_tfms=item_tfms,
                 batch_tfms=batch_tfms)

Using Summary

Now to run .summary, we need to send in what our DataBlock expects. In this case it's a path (think how we make our DataLoaders from the DataBlock)

pets.summary(path)
Setting-up type transforms pipelines
Collecting items from /root/.fastai/data/imagewoof2
Found 12954 items
2 datasets of sizes 10364,2590
Setting up Pipeline: PILBase.create
Setting up Pipeline: parent_label -> dict.__getitem__ -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}

Building one sample
  Pipeline: PILBase.create
    starting from
      /root/.fastai/data/imagewoof2/train/n02086240/n02086240_6168.JPEG
    applying PILBase.create gives
      PILImage mode=RGB size=500x375
  Pipeline: parent_label -> dict.__getitem__ -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}
    starting from
      /root/.fastai/data/imagewoof2/train/n02086240/n02086240_6168.JPEG
    applying parent_label gives
      n02086240
    applying dict.__getitem__ gives
      Shih-Tzu
    applying Categorize -- {'vocab': None, 'sort': True, 'add_na': False} gives
      TensorCategory(9)

Final sample: (PILImage mode=RGB size=500x375, TensorCategory(9))


Collecting items from /root/.fastai/data/imagewoof2
Found 12954 items
2 datasets of sizes 10364,2590
Setting up Pipeline: PILBase.create
Setting up Pipeline: parent_label -> dict.__getitem__ -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}
Setting up after_item: Pipeline: Resize -- {'size': (128, 128), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} -> ToTensor
Setting up before_batch: Pipeline: 
Setting up after_batch: Pipeline: IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} -> Flip -- {'size': 224, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 0.5} -> Brightness -- {'max_lighting': 0.2, 'p': 1.0, 'draw': None, 'batch': False} -> Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)}

Building one batch
Applying item_tfms to the first sample:
  Pipeline: Resize -- {'size': (128, 128), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} -> ToTensor
    starting from
      (PILImage mode=RGB size=500x375, TensorCategory(9))
    applying Resize -- {'size': (128, 128), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} gives
      (PILImage mode=RGB size=128x128, TensorCategory(9))
    applying ToTensor gives
      (TensorImage of size 3x128x128, TensorCategory(9))

Adding the next 3 samples

No before_batch transform to apply

Collating items in a batch

Applying batch_tfms to the batch built
  Pipeline: IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} -> Flip -- {'size': 224, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 0.5} -> Brightness -- {'max_lighting': 0.2, 'p': 1.0, 'draw': None, 'batch': False} -> Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)}
    starting from
      (TensorImage of size 4x3x128x128, TensorCategory([9, 9, 5, 0], device='cuda:0'))
    applying IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} gives
      (TensorImage of size 4x3x128x128, TensorCategory([9, 9, 5, 0], device='cuda:0'))
    applying Flip -- {'size': 224, 'mode': 'bilinear', 'pad_mode': 'reflection', 'mode_mask': 'nearest', 'align_corners': True, 'p': 0.5} gives
      (TensorImage of size 4x3x224x224, TensorCategory([9, 9, 5, 0], device='cuda:0'))
    applying Brightness -- {'max_lighting': 0.2, 'p': 1.0, 'draw': None, 'batch': False} gives
      (TensorImage of size 4x3x224x224, TensorCategory([9, 9, 5, 0], device='cuda:0'))
    applying Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)} gives
      (TensorImage of size 4x3x224x224, TensorCategory([9, 9, 5, 0], device='cuda:0'))

Debugging without the DataBlock

What we find is it will go through each and every single part of our DataBlock, test it on an item, and we can see what popped out! But! What if we are using the Datasets instead? Let's go through how to utilize it

tfms = [[PILImage.create], [parent_label, Categorize()]]
item_tfms = [ToTensor(), Resize(128)]
batch_tfms = [FlipItem(), RandomResizedCrop(128, min_scale=0.35),
              IntToFloatTensor(), Normalize.from_stats(*imagenet_stats)]
items = get_image_files(path)
split_idx = GrandparentSplitter(valid_name='val')(items)
dsets = Datasets(items, tfms, splits=split_idx)
dls = dsets.dataloaders(after_item=item_tfms, after_batch=batch_tfms, bs=64)

We'll want to grab the first item from our set

x = dsets.train[0]
x
(PILImage mode=RGB size=360x303, TensorCategory(6))

And pass it into any after_item or after_batch transform Pipeline. We can list them by calling them

dls.train.after_item
Pipeline: Resize -- {'size': (128, 128), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} -> ToTensor
dls.train.after_batch
Pipeline: FlipItem -- {'p': 0.5} -> RandomResizedCrop -- {'size': (128, 128), 'min_scale': 0.35, 'ratio': (0.75, 1.3333333333333333), 'resamples': (2, 0), 'val_xtra': 0.14, 'p': 1.0} -> IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} -> Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)}

And now we can pass in our item through the Pipeline like so:

(x[0] has our input and x[1] has our y)

for f in dls.train.after_item:
  name = f.name
  x = f(x)
  print(name, x[0])
Resize -- {'size': (128, 128), 'method': 'crop', 'pad_mode': 'reflection', 'resamples': (2, 0), 'p': 1.0} PILImage mode=RGB size=128x128
ToTensor TensorImage([[[ 16,  20,  24,  ..., 151, 134, 137],
         [ 27,  26,  32,  ..., 146, 151, 136],
         [ 43,  46,  47,  ..., 123, 142, 143],
         ...,
         [145, 134, 106,  ...,  51,  37,  27],
         [ 38,  55,  46,  ...,  33,  35,  23],
         [ 64,  85,  66,  ...,  33,  53,  56]],

        [[ 18,  18,  22,  ..., 150, 132, 135],
         [ 29,  25,  30,  ..., 144, 149, 134],
         [ 46,  44,  45,  ..., 119, 140, 141],
         ...,
         [143, 144, 117,  ...,  71,  77,  67],
         [ 51,  78,  75,  ...,  49,  50,  37],
         [ 76, 105,  89,  ...,  50,  67,  69]],

        [[ 29,  32,  36,  ..., 106,  90,  94],
         [ 40,  38,  44,  ..., 107, 109,  93],
         [ 56,  58,  59,  ...,  90, 100, 100],
         ...,
         [142, 121,  92,  ...,  61,  54,  45],
         [ 42,  67,  45,  ...,  38,  39,  26],
         [ 61,  89,  61,  ...,  33,  55,  59]]], dtype=torch.uint8)
for f in dls.train.after_batch:
  name = f.name
  x = f(to_device(x, 'cuda')) # we need to move our data to the GPU
  print(name, x[0])
FlipItem -- {'p': 0.5} TensorImage([[[0.0627, 0.0784, 0.0941,  ..., 0.5922, 0.5255, 0.5373],
         [0.1059, 0.1020, 0.1255,  ..., 0.5725, 0.5922, 0.5333],
         [0.1686, 0.1804, 0.1843,  ..., 0.4824, 0.5569, 0.5608],
         ...,
         [0.5686, 0.5255, 0.4157,  ..., 0.2000, 0.1451, 0.1059],
         [0.1490, 0.2157, 0.1804,  ..., 0.1294, 0.1373, 0.0902],
         [0.2510, 0.3333, 0.2588,  ..., 0.1294, 0.2078, 0.2196]],

        [[0.0706, 0.0706, 0.0863,  ..., 0.5882, 0.5176, 0.5294],
         [0.1137, 0.0980, 0.1176,  ..., 0.5647, 0.5843, 0.5255],
         [0.1804, 0.1725, 0.1765,  ..., 0.4667, 0.5490, 0.5529],
         ...,
         [0.5608, 0.5647, 0.4588,  ..., 0.2784, 0.3020, 0.2627],
         [0.2000, 0.3059, 0.2941,  ..., 0.1922, 0.1961, 0.1451],
         [0.2980, 0.4118, 0.3490,  ..., 0.1961, 0.2627, 0.2706]],

        [[0.1137, 0.1255, 0.1412,  ..., 0.4157, 0.3529, 0.3686],
         [0.1569, 0.1490, 0.1725,  ..., 0.4196, 0.4275, 0.3647],
         [0.2196, 0.2275, 0.2314,  ..., 0.3529, 0.3922, 0.3922],
         ...,
         [0.5569, 0.4745, 0.3608,  ..., 0.2392, 0.2118, 0.1765],
         [0.1647, 0.2627, 0.1765,  ..., 0.1490, 0.1529, 0.1020],
         [0.2392, 0.3490, 0.2392,  ..., 0.1294, 0.2157, 0.2314]]],
       device='cuda:0')
RandomResizedCrop -- {'size': (128, 128), 'min_scale': 0.35, 'ratio': (0.75, 1.3333333333333333), 'resamples': (2, 0), 'val_xtra': 0.14, 'p': 1.0} TensorImage([[[0.0627, 0.0784, 0.0941,  ..., 0.5922, 0.5255, 0.5373],
         [0.1059, 0.1020, 0.1255,  ..., 0.5725, 0.5922, 0.5333],
         [0.1686, 0.1804, 0.1843,  ..., 0.4824, 0.5569, 0.5608],
         ...,
         [0.5686, 0.5255, 0.4157,  ..., 0.2000, 0.1451, 0.1059],
         [0.1490, 0.2157, 0.1804,  ..., 0.1294, 0.1373, 0.0902],
         [0.2510, 0.3333, 0.2588,  ..., 0.1294, 0.2078, 0.2196]],

        [[0.0706, 0.0706, 0.0863,  ..., 0.5882, 0.5176, 0.5294],
         [0.1137, 0.0980, 0.1176,  ..., 0.5647, 0.5843, 0.5255],
         [0.1804, 0.1725, 0.1765,  ..., 0.4667, 0.5490, 0.5529],
         ...,
         [0.5608, 0.5647, 0.4588,  ..., 0.2784, 0.3020, 0.2627],
         [0.2000, 0.3059, 0.2941,  ..., 0.1922, 0.1961, 0.1451],
         [0.2980, 0.4118, 0.3490,  ..., 0.1961, 0.2627, 0.2706]],

        [[0.1137, 0.1255, 0.1412,  ..., 0.4157, 0.3529, 0.3686],
         [0.1569, 0.1490, 0.1725,  ..., 0.4196, 0.4275, 0.3647],
         [0.2196, 0.2275, 0.2314,  ..., 0.3529, 0.3922, 0.3922],
         ...,
         [0.5569, 0.4745, 0.3608,  ..., 0.2392, 0.2118, 0.1765],
         [0.1647, 0.2627, 0.1765,  ..., 0.1490, 0.1529, 0.1020],
         [0.2392, 0.3490, 0.2392,  ..., 0.1294, 0.2157, 0.2314]]],
       device='cuda:0')
IntToFloatTensor -- {'div': 255.0, 'div_mask': 1} TensorImage([[[0.0002, 0.0003, 0.0004,  ..., 0.0023, 0.0021, 0.0021],
         [0.0004, 0.0004, 0.0005,  ..., 0.0022, 0.0023, 0.0021],
         [0.0007, 0.0007, 0.0007,  ..., 0.0019, 0.0022, 0.0022],
         ...,
         [0.0022, 0.0021, 0.0016,  ..., 0.0008, 0.0006, 0.0004],
         [0.0006, 0.0008, 0.0007,  ..., 0.0005, 0.0005, 0.0004],
         [0.0010, 0.0013, 0.0010,  ..., 0.0005, 0.0008, 0.0009]],

        [[0.0003, 0.0003, 0.0003,  ..., 0.0023, 0.0020, 0.0021],
         [0.0004, 0.0004, 0.0005,  ..., 0.0022, 0.0023, 0.0021],
         [0.0007, 0.0007, 0.0007,  ..., 0.0018, 0.0022, 0.0022],
         ...,
         [0.0022, 0.0022, 0.0018,  ..., 0.0011, 0.0012, 0.0010],
         [0.0008, 0.0012, 0.0012,  ..., 0.0008, 0.0008, 0.0006],
         [0.0012, 0.0016, 0.0014,  ..., 0.0008, 0.0010, 0.0011]],

        [[0.0004, 0.0005, 0.0006,  ..., 0.0016, 0.0014, 0.0014],
         [0.0006, 0.0006, 0.0007,  ..., 0.0016, 0.0017, 0.0014],
         [0.0009, 0.0009, 0.0009,  ..., 0.0014, 0.0015, 0.0015],
         ...,
         [0.0022, 0.0019, 0.0014,  ..., 0.0009, 0.0008, 0.0007],
         [0.0006, 0.0010, 0.0007,  ..., 0.0006, 0.0006, 0.0004],
         [0.0009, 0.0014, 0.0009,  ..., 0.0005, 0.0008, 0.0009]]],
       device='cuda:0')
Normalize -- {'mean': tensor([[[[0.4850]],

         [[0.4560]],

         [[0.4060]]]], device='cuda:0'), 'std': tensor([[[[0.2290]],

         [[0.2240]],

         [[0.2250]]]], device='cuda:0'), 'axes': (0, 2, 3)} TensorImage([[[[-2.1168, -2.1166, -2.1163,  ..., -2.1078, -2.1089, -2.1087],
          [-2.1161, -2.1162, -2.1158,  ..., -2.1081, -2.1078, -2.1088],
          [-2.1150, -2.1148, -2.1147,  ..., -2.1096, -2.1084, -2.1083],
          ...,
          [-2.1082, -2.1089, -2.1108,  ..., -2.1145, -2.1154, -2.1161],
          [-2.1154, -2.1142, -2.1148,  ..., -2.1157, -2.1156, -2.1164],
          [-2.1136, -2.1122, -2.1135,  ..., -2.1157, -2.1143, -2.1141]],

         [[-2.0345, -2.0345, -2.0342,  ..., -2.0254, -2.0267, -2.0264],
          [-2.0337, -2.0340, -2.0337,  ..., -2.0258, -2.0255, -2.0265],
          [-2.0326, -2.0327, -2.0326,  ..., -2.0275, -2.0261, -2.0260],
          ...,
          [-2.0259, -2.0258, -2.0277,  ..., -2.0308, -2.0304, -2.0311],
          [-2.0322, -2.0304, -2.0306,  ..., -2.0324, -2.0323, -2.0332],
          [-2.0305, -2.0285, -2.0296,  ..., -2.0323, -2.0311, -2.0310]],

         [[-1.8025, -1.8023, -1.8020,  ..., -1.7972, -1.7983, -1.7980],
          [-1.8017, -1.8018, -1.8014,  ..., -1.7971, -1.7970, -1.7981],
          [-1.8006, -1.8005, -1.8004,  ..., -1.7983, -1.7976, -1.7976],
          ...,
          [-1.7947, -1.7962, -1.7982,  ..., -1.8003, -1.8008, -1.8014],
          [-1.8016, -1.7999, -1.8014,  ..., -1.8018, -1.8018, -1.8027],
          [-1.8003, -1.7984, -1.8003,  ..., -1.8022, -1.8007, -1.8004]]]],
       device='cuda:0')