I am working on a multitask problem, where I feed in an image (in this case, multi-spectral, but not super important) and receive both regression and categorization outputs. However, I’m hitting roadbumps and am curious if people have had success. I think this is very similar to the multi-task problem that was solved by @yang-zhang for fasta v1, but I haven’t seen a fastai v2 solution.
To do this, I created my DataBlock that expects an Image-like input, and then (thanks to n_inp=1
) yields two outputs: a RegressionBlock and a CategoryBlock:
our_datablocks = (MSTensorImage(x = 12), RegressionBlock, CategoryBlock)
db = DataBlock(blocks = our_datablocks,
get_items = find_image_zip_files,
get_x = get_x_fn,
get_y = (get_y_fn_age, get_y_fn_disease),
n_inp=1 # Declare that only the first datablock is input
)
dls = db.dataloaders(source = path/'', bs = 2)
-----
Collecting items ...
Found 20 items
2 datasets of sizes 16,4
Setting up Pipeline: get_x_fn
Setting up Pipeline: get_y_fn_age -> RegressionSetup -- {'c': None}
Setting up Pipeline: get_y_fn_disease -> Categorize -- {'vocab': None, 'sort': True, 'add_na': False}
So far, so good.
But creating the model itself, the problem becomes apparent:
learn = cnn_learner(dls = dls,
arch = resnet18,
n_in=12,
loss_func = (MSELossFlat(), CrossEntropyLossFlat()),
normalize = False,
pretrained = True)
Clearly, unless fastai v2 knows what I mean by that list of loss functions and does a lot of work behind the scenes in cnn_learner
, that’s not going to work. And sure enough, it does not:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-91-e1fdee3ccda7> in <module>
----> 1 learn = cnn_learner(dls = dls,
2 arch = resnet18,
3 n_in=12,
4 loss_func = (MSELossFlat(), CrossEntropyLossFlat()),
5 normalize = False,
/Library/Frameworks/Python.framework/Versions/3.9/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)
178 if n_out is None: n_out = get_c(dls)
179 assert n_out, "`n_out` is not defined, and could not be inferred from data, set `dls.c` or pass `n_out`"
--> 180 model = create_cnn_model(arch, n_out, pretrained=pretrained, **kwargs)
181
182 splitter=ifnone(splitter, meta['split'])
/Library/Frameworks/Python.framework/Versions/3.9/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)
/Library/Frameworks/Python.framework/Versions/3.9/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))
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/fastai/layers.py in __init__(self, n_in, n_out, bn, p, act, lin_first)
169 layers = [BatchNorm(n_out if lin_first else n_in, ndim=1)] if bn else []
170 if p != 0: layers.append(nn.Dropout(p))
--> 171 lin = [nn.Linear(n_in, n_out, bias=not bn)]
172 if act is not None: lin.append(act)
173 layers = lin+layers if lin_first else layers+lin
/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/torch/nn/modules/linear.py in __init__(self, in_features, out_features, bias)
76 self.in_features = in_features
77 self.out_features = out_features
---> 78 self.weight = Parameter(torch.Tensor(out_features, in_features))
79 if bias:
80 self.bias = Parameter(torch.Tensor(out_features))
TypeError: new() received an invalid combination of arguments - got (L, int), but expected one of:
* (*, torch.device device)
didn't match because some of the arguments have invalid types: (L, int)
* (torch.Storage storage)
* (Tensor other)
* (tuple of ints size, *, torch.device device)
* (object data, *, torch.device device)
So I think that the next step is to create a custom head and a custom loss function. However, I’m curious if this is already a solved problem and someone has succeeded here already.