All the functions necessary to build `Learner` suitable for transfer learning in computer vision
from nbdev.showdoc import *

Cut a pretrained model

m = nn.Sequential(nn.AdaptiveAvgPool2d(5), nn.Linear(2,3), nn.Conv2d(2,3,1), nn.MaxPool3d(5))
test_eq([bool(_is_pool_type(m_)) for m_ in m.children()], [True,False,False,True])

has_pool_type[source]

has_pool_type(m)

Return True if m is a pooling layer or has one in its children

m = nn.Sequential(nn.AdaptiveAvgPool2d(5), nn.Linear(2,3), nn.Conv2d(2,3,1), nn.MaxPool3d(5))
assert has_pool_type(m)
test_eq([has_pool_type(m_) for m_ in m.children()], [True,False,False,True])

create_body[source]

create_body(arch, n_in=3, pretrained=True, cut=None)

Cut off the body of a typically pretrained arch as determined by cut

cut can either be an integer, in which case we cut the model at the coresponding layer, or a function, in which case, this funciton returns cut(model). It defaults to cnn_config(arch)['cut'] if arch is in cnn_config, otherwise to the first layer that contains some pooling.

tst = lambda pretrained : nn.Sequential(nn.Conv2d(3,5,3), nn.BatchNorm2d(5), nn.AvgPool2d(1), nn.Linear(3,4))
m = create_body(tst)
test_eq(len(m), 2)

m = create_body(tst, cut=3)
test_eq(len(m), 3)

m = create_body(tst, cut=noop)
test_eq(len(m), 4)

for n in range(1,5):    
    m = create_body(tst, n_in=n)
    test_eq(_get_first_layer(m)[0].in_channels, n)

Head and model

create_head[source]

create_head(nf, n_out, lin_ftrs=None, ps=0.5, concat_pool=True, bn_final=False, lin_first=False, y_range=None)

Model head that takes nf features, runs through lin_ftrs, and out n_out classes.

tst = create_head(5, 10)
tst
Sequential(
  (0): AdaptiveConcatPool2d(
    (ap): AdaptiveAvgPool2d(output_size=1)
    (mp): AdaptiveMaxPool2d(output_size=1)
  )
  (1): Flatten(full=False)
  (2): BatchNorm1d(5, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (3): Dropout(p=0.25, inplace=False)
  (4): Linear(in_features=5, out_features=512, bias=False)
  (5): ReLU(inplace=True)
  (6): BatchNorm1d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
  (7): Dropout(p=0.5, inplace=False)
  (8): Linear(in_features=512, out_features=10, bias=False)
)

create_cnn_model[source]

create_cnn_model(arch, n_out, cut, pretrained, n_in=3, lin_ftrs=None, ps=0.5, custom_head=None, bn_final=False, concat_pool=True, y_range=None, init='kaiming_normal_')

Create custom convnet architecture using base_arch

tst = create_cnn_model(models.resnet18, 10, None, True)
tst = create_cnn_model(models.resnet18, 10, None, True, n_in=1)

cnn_config[source]

cnn_config(n_in=3, lin_ftrs=None, ps=0.5, custom_head=None, bn_final=False, concat_pool=True, y_range=None, init='kaiming_normal_')

Convenience function to easily create a config for create_cnn_model

pets = DataBlock(blocks=(ImageBlock, CategoryBlock), 
                 get_items=get_image_files, 
                 splitter=RandomSplitter(),
                 get_y=RegexLabeller(pat = r'/([^/]+)_\d+.jpg$'))

dls = pets.dataloaders(untar_data(URLs.PETS)/"images", item_tfms=RandomResizedCrop(300, min_scale=0.5), bs=64,
                        batch_tfms=[*aug_transforms(size=224)])
#TODO: refactor, i.e. something like this?
# class ModelSplitter():
#     def __init__(self, idx): self.idx = idx
#     def split(self, m): return L(m[:self.idx], m[self.idx:]).map(params)
#     def __call__(self,): return {'cut':self.idx, 'split':self.split}

default_split[source]

default_split(m:Module)

Learner convenience functions

cnn_learner[source]

cnn_learner(dls, arch, loss_func=None, pretrained=True, cut=None, splitter=None, y_range=None, config=None, n_in=3, n_out=None, normalize=True, opt_func='Adam', lr=0.001, cbs=None, metrics=None, path=None, model_dir='models', wd=None, wd_bn_bias=False, train_bn=True, moms=(0.95, 0.85, 0.95))

Build a convnet style learner

The model is built from arch using the number of final activation inferred from dls by get_c. It might be pretrained and the architecture is cut and split using the default metadata of the model architecture (this can be customized by passing a cut or a splitter). To customize the model creation, use cnn_config and pass the result to the config argument.

learn = cnn_learner(dls, models.resnet34, loss_func=CrossEntropyLossFlat(), config=cnn_config(ps=0.25))
test_eq(to_cpu(dls.after_batch[1].mean[0].squeeze()), tensor(imagenet_stats[0]))

unet_config[source]

unet_config(blur=False, blur_final=True, self_attention=False, y_range=None, last_cross=True, bottle=False, act_cls='ReLU', init='kaiming_normal_', norm_type=None)

Convenience function to easily create a config for DynamicUnet

unet_learner[source]

unet_learner(dls, arch, loss_func=None, pretrained=True, cut=None, splitter=None, config=None, n_in=3, n_out=None, normalize=True, opt_func='Adam', lr=0.001, cbs=None, metrics=None, path=None, model_dir='models', wd=None, wd_bn_bias=False, train_bn=True, moms=(0.95, 0.85, 0.95))

Build a unet learner from dls and arch

camvid = DataBlock(blocks=(ImageBlock, MaskBlock),
                   get_items=get_image_files,
                   splitter=RandomSplitter(),
                   get_y=lambda o: untar_data(URLs.CAMVID_TINY)/'labels'/f'{o.stem}_P{o.suffix}')

dls = camvid.dataloaders(untar_data(URLs.CAMVID_TINY)/"images", batch_tfms=aug_transforms())
dls.show_batch(max_n=9, vmin=1, vmax=30)
#TODO: Find a way to pass the classes properly
dls.vocab = np.loadtxt(untar_data(URLs.CAMVID_TINY)/'codes.txt', dtype=str)
learn = unet_learner(dls, models.resnet34, loss_func=CrossEntropyLossFlat(axis=1))
learn = unet_learner(dls, models.resnet34, pretrained=True, n_in=4)

Show functions

(TensorImage,TensorImage) -> show_results (TensorImage,TensorCategory) -> show_results (TensorImage,TensorMask) -> show_results (TensorImage,TensorBBox) -> show_results (TensorImage,TensorPoint) -> show_results (TensorImage,object) -> show_results (object,object) -> show_results[source]

(TensorImage,TensorImage) -> show_results (TensorImage,TensorCategory) -> show_results (TensorImage,TensorMask) -> show_results (TensorImage,TensorBBox) -> show_results (TensorImage,TensorPoint) -> show_results (TensorImage,object) -> show_results (object,object) -> show_results()

Dictionary-like object; __getitem__ matches keys of types using issubclass