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)


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(
)
(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.show_batch(max_n=9, vmin=1, vmax=30)

#TODO: Find a way to pass the classes properly

learn = unet_learner(dls, models.resnet34, loss_func=CrossEntropyLossFlat(axis=1))

(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