I am trying to create a model for doing two separate classifications on a single image. Here is a silly example:
from fastai.vision.all import *
path = untar_data(URLs.MNIST, dest="data")
Path.BASE_PATH = path
def is_even(filepath): return int(filepath.parent.name) % 2 == 0
block = DataBlock(
blocks=(ImageBlock, CategoryBlock, CategoryBlock),
get_items=get_image_files,
splitter=RandomSplitter(valid_pct=0.2, seed=42),
get_y=[parent_label, is_even],
n_inp=1)
loaders = block.dataloaders(path/"training")
learn = cnn_learner(loaders, resnet34, metrics=accuracy)
However this gives me the following error:
/home/ak/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/torch/nn/functional.py:718: UserWarning: Named tensors and all their associated APIs are an experimental feature and subject to change. Please do not use them for anything important until they are released as stable. (Triggered internally at /pytorch/c10/core/TensorImpl.h:1156.)
return torch.max_pool2d(input, kernel_size, stride, padding, dilation, ceil_mode)
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
/tmp/ipykernel_7772/3687905282.py in <module>
----> 1 learn = cnn_learner(loaders, resnet34, metrics=accuracy)
~/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/fastai/vision/learner.py in cnn_learner(dls, arch, normalize, n_out, pretrained, config, loss_func, opt_func, lr, splitter, cbs, metrics, path, model_dir, wd, wd_bn_bias, train_bn, moms, **kwargs)
177 if n_out is None: n_out = get_c(dls)
178 assert n_out, "`n_out` is not defined, and could not be inferred from data, set `dls.c` or pass `n_out`"
--> 179 model = create_cnn_model(arch, n_out, pretrained=pretrained, **kwargs)
180
181 splitter=ifnone(splitter, meta['split'])
~/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/fastai/vision/learner.py in create_cnn_model(arch, n_out, pretrained, cut, n_in, init, custom_head, concat_pool, **kwargs)
144 if custom_head is None:
145 nf = num_features_model(nn.Sequential(*body.children()))
--> 146 head = create_head(nf, n_out, concat_pool=concat_pool, **kwargs)
147 else: head = custom_head
148 model = nn.Sequential(body, head)
~/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/fastai/vision/learner.py in create_head(nf, n_out, lin_ftrs, ps, concat_pool, first_bn, bn_final, lin_first, y_range)
87 if lin_first: layers.append(nn.Dropout(ps.pop(0)))
88 for ni,no,bn,p,actn in zip(lin_ftrs[:-1], lin_ftrs[1:], bns, ps, actns):
---> 89 layers += LinBnDrop(ni, no, bn=bn, p=p, act=actn, lin_first=lin_first)
90 if lin_first: layers.append(nn.Linear(lin_ftrs[-2], n_out))
91 if bn_final: layers.append(nn.BatchNorm1d(lin_ftrs[-1], momentum=0.01))
~/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/fastai/layers.py in __init__(self, n_in, n_out, bn, p, act, lin_first)
175 layers = [BatchNorm(n_out if lin_first else n_in, ndim=1)] if bn else []
176 if p != 0: layers.append(nn.Dropout(p))
--> 177 lin = [nn.Linear(n_in, n_out, bias=not bn)]
178 if act is not None: lin.append(act)
179 layers = lin+layers if lin_first else layers+lin
~/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/torch/nn/modules/linear.py in __init__(self, in_features, out_features, bias, device, dtype)
79 self.in_features = in_features
80 self.out_features = out_features
---> 81 self.weight = Parameter(torch.empty((out_features, in_features), **factory_kwargs))
82 if bias:
83 self.bias = Parameter(torch.empty(out_features, **factory_kwargs))
TypeError: empty() received an invalid combination of arguments - got (tuple, dtype=NoneType, device=NoneType), but expected one of:
* (tuple of ints size, *, tuple of names names, torch.memory_format memory_format, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
* (tuple of ints size, *, torch.memory_format memory_format, Tensor out, torch.dtype dtype, torch.layout layout, torch.device device, bool pin_memory, bool requires_grad)
I looked into it some more with %debug:
> /home/ak/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/torch/nn/modules/linear.py(81)__init__()
79 self.in_features = in_features
80 self.out_features = out_features
---> 81 self.weight = Parameter(torch.empty((out_features, in_features), **factory_kwargs))
82 if bias:
83 self.bias = Parameter(torch.empty(out_features, **factory_kwargs))
ipdb> out_features
[10, 2]
ipdb> up
> /home/ak/.local/share/virtualenvs/pytorch-S1U3fvgi/lib/python3.9/site-packages/fastai/layers.py(177)__init__()
175 layers = [BatchNorm(n_out if lin_first else n_in, ndim=1)] if bn else []
176 if p != 0: layers.append(nn.Dropout(p))
--> 177 lin = [nn.Linear(n_in, n_out, bias=not bn)]
178 if act is not None: lin.append(act)
179 layers = lin+layers if lin_first else layers+lin
ipdb> n_out
[10, 2]
I think nn.Linear expects a number as n_out
parameter, but it looks like my two CategoryBlocks were passed in as two seperate numbers.
The documentation I found on using multiple DataBlocks as output shows you how to create the DataBlock/dataloader, but not how to feed this into the learner.
Does someone know how to do this right?