Creating Learner -> AttributeError: 'function' object has no attribute 'to'

I’m trying to create a Learner object to use on the Brain MRI Segmentation dataset on Kaggle. The task I’m trying to carry out is just train an image and its corresponding bounding box (given a mask for that image).
I’m running into the issue of AttributeError: 'function' object has no attribute 'to' relating to the model being passed into the parameter.

AttributeError                            Traceback (most recent call last)
<ipython-input-28-04c1d2b56ffa> in <module>
      1 # create the Learner
      2 learner_box = Learner(dls = bbDataLoader,
----> 3                      model = models.resnet50
      4                      )

/opt/conda/lib/python3.7/site-packages/fastcore/utils.py in _f(*args, **kwargs)
    429         init_args.update(log)
    430         setattr(inst, 'init_args', init_args)
--> 431         return inst if to_return else f(*args, **kwargs)
    432     return _f
    433 

/opt/conda/lib/python3.7/site-packages/fastai2/learner.py in __init__(self, dls, model, loss_func, opt_func, lr, splitter, cbs, metrics, path, model_dir, wd, wd_bn_bias, train_bn, moms)
     91         self.path = Path(path) if path is not None else getattr(dls, 'path', Path('.'))
     92         self.add_cbs([(cb() if isinstance(cb, type) else cb) for cb in L(defaults.callbacks)+L(cbs)])
---> 93         self.model.to(self.dls.device)
     94         if hasattr(self.model, 'reset'): self.model.reset()
     95         self.epoch,self.n_epoch,self.loss = 0,1,tensor(0.)

AttributeError: 'function' object has no attribute 'to'

The notebook where I’m running this code can be found here: https://www.kaggle.com/sanjan611/brain-mri-segmentation-fastai-v2

Is this an issue with the model I am using?

You need to pass the model, not the function.

models.resnet50 = function

models.resnet50(c_out=10) = model.

Also fair warning the model itself won’t work for your task like that. You should look into bounding box architectures such as RetinaNet, as just a resnet won’t due without modifications.

1 Like

Okay that’s useful to know, thanks! The use of resnet is just for an experimentation for another project.
So I’ve created a custom class for doing this:

class BBoxDetect(nn.Module):
    def __init__(self, arch= models.resnet18):
        super().__init__()
        self.cnn = create_body(arch)
        self.head = create_head(num_features_model(self.cnn) * 2, 4)

    def forward(self, image):
        x = self.cnn(image)
        x = self.head(x)
        return 2 * (x.sigmoid_() - 0.5)
    
model = BBoxDetect(arch = models.resnet18)

But now I’m running into a new error while training with fit_one_cycle.

epochs = 10
cbs = [ShowGraphCallback()]
lrs = 1e-4

learner_box.fit_one_cycle(n_epoch = epochs, lr_max = lrs, pct_start=0.7, cbs = cbs)

Would you know what this means? The Kaggle notebook should be updated.

> ---------------------------------------------------------------------------
> TypeError                                 Traceback (most recent call last)
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in fit(self, n_epoch, lr, wd, cbs, reset_opt)
>     199                         self.epoch=epoch;          self('begin_epoch')
> --> 200                         self._do_epoch_train()
>     201                         self._do_epoch_validate()
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in _do_epoch_train(self)
>     174             self.dl = self.dls.train;                        self('begin_train')
> --> 175             self.all_batches()
>     176         except CancelTrainException:                         self('after_cancel_train')
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in all_batches(self)
>     152         self.n_iter = len(self.dl)
> --> 153         for o in enumerate(self.dl): self.one_batch(*o)
>     154 
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in one_batch(self, i, b)
>     160             if len(self.yb) == 0: return
> --> 161             self.loss = self.loss_func(self.pred, *self.yb); self('after_loss')
>     162             if not self.training: return
> 
> TypeError: __call__() takes 3 positional arguments but 4 were given
> 
> During handling of the above exception, another exception occurred:
> 
> IndexError                                Traceback (most recent call last)
> <ipython-input-76-06eed37350e0> in <module>
>       3 lrs = 1e-4
>       4 
> ----> 5 learner_box.fit_one_cycle(n_epoch = epochs, lr_max = lrs, pct_start=0.7, cbs = cbs) # added the cbs here
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/utils.py in _f(*args, **kwargs)
>     429         init_args.update(log)
>     430         setattr(inst, 'init_args', init_args)
> --> 431         return inst if to_return else f(*args, **kwargs)
>     432     return _f
>     433 
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/callback/schedule.py in fit_one_cycle(self, n_epoch, lr_max, div, div_final, pct_start, wd, moms, cbs, reset_opt)
>     111     scheds = {'lr': combined_cos(pct_start, lr_max/div, lr_max, lr_max/div_final),
>     112               'mom': combined_cos(pct_start, *(self.moms if moms is None else moms))}
> --> 113     self.fit(n_epoch, cbs=ParamScheduler(scheds)+L(cbs), reset_opt=reset_opt, wd=wd)
>     114 
>     115 # Cell
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/utils.py in _f(*args, **kwargs)
>     429         init_args.update(log)
>     430         setattr(inst, 'init_args', init_args)
> --> 431         return inst if to_return else f(*args, **kwargs)
>     432     return _f
>     433 
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in fit(self, n_epoch, lr, wd, cbs, reset_opt)
>     201                         self._do_epoch_validate()
>     202                     except CancelEpochException:   self('after_cancel_epoch')
> --> 203                     finally:                       self('after_epoch')
>     204 
>     205             except CancelFitException:             self('after_cancel_fit')
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in __call__(self, event_name)
>     132     def ordered_cbs(self, event): return [cb for cb in sort_by_run(self.cbs) if hasattr(cb, event)]
>     133 
> --> 134     def __call__(self, event_name): L(event_name).map(self._call_one)
>     135     def _call_one(self, event_name):
>     136         assert hasattr(event, event_name)
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in map(self, f, *args, **kwargs)
>     375              else f.format if isinstance(f,str)
>     376              else f.__getitem__)
> --> 377         return self._new(map(g, self))
>     378 
>     379     def filter(self, f, negate=False, **kwargs):
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in _new(self, items, *args, **kwargs)
>     325     @property
>     326     def _xtra(self): return None
> --> 327     def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
>     328     def __getitem__(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
>     329     def copy(self): return self._new(self.items.copy())
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in __call__(cls, x, *args, **kwargs)
>      45             return x
>      46 
> ---> 47         res = super().__call__(*((x,) + args), **kwargs)
>      48         res._newchk = 0
>      49         return res
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in __init__(self, items, use_list, match, *rest)
>     316         if items is None: items = []
>     317         if (use_list is not None) or not _is_array(items):
> --> 318             items = list(items) if use_list else _listify(items)
>     319         if match is not None:
>     320             if is_coll(match): match = len(match)
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in _listify(o)
>     252     if isinstance(o, list): return o
>     253     if isinstance(o, str) or _is_array(o): return [o]
> --> 254     if is_iter(o): return list(o)
>     255     return [o]
>     256 
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in __call__(self, *args, **kwargs)
>     218             if isinstance(v,_Arg): kwargs[k] = args.pop(v.i)
>     219         fargs = [args[x.i] if isinstance(x, _Arg) else x for x in self.pargs] + args[self.maxi+1:]
> --> 220         return self.fn(*fargs, **kwargs)
>     221 
>     222 # Cell
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in _call_one(self, event_name)
>     135     def _call_one(self, event_name):
>     136         assert hasattr(event, event_name)
> --> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
>     138 
>     139     def _bn_bias_state(self, with_bias): return bn_bias_params(self.model, with_bias).map(self.opt.state)
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/learner.py in <listcomp>(.0)
>     135     def _call_one(self, event_name):
>     136         assert hasattr(event, event_name)
> --> 137         [cb(event_name) for cb in sort_by_run(self.cbs)]
>     138 
>     139     def _bn_bias_state(self, with_bias): return bn_bias_params(self.model, with_bias).map(self.opt.state)
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/callback/core.py in __call__(self, event_name)
>      22         _run = (event_name not in _inner_loop or (self.run_train and getattr(self, 'training', True)) or
>      23                (self.run_valid and not getattr(self, 'training', False)))
> ---> 24         if self.run and _run: getattr(self, event_name, noop)()
>      25         if event_name=='after_fit': self.run=True #Reset self.run to True at each end of fit
>      26 
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/callback/progress.py in after_epoch(self)
>      83         rec = self.learn.recorder
>      84         iters = range_of(rec.losses)
> ---> 85         val_losses = [v[1] for v in rec.values]
>      86         x_bounds = (0, (self.n_epoch - len(self.nb_batches)) * self.nb_batches[0] + len(rec.losses))
>      87         y_bounds = (0, max((max(Tensor(rec.losses)), max(Tensor(val_losses)))))
> 
> /opt/conda/lib/python3.7/site-packages/fastai2/callback/progress.py in <listcomp>(.0)
>      83         rec = self.learn.recorder
>      84         iters = range_of(rec.losses)
> ---> 85         val_losses = [v[1] for v in rec.values]
>      86         x_bounds = (0, (self.n_epoch - len(self.nb_batches)) * self.nb_batches[0] + len(rec.losses))
>      87         y_bounds = (0, max((max(Tensor(rec.losses)), max(Tensor(val_losses)))))
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in __getitem__(self, idx)
>     326     def _xtra(self): return None
>     327     def _new(self, items, *args, **kwargs): return type(self)(items, *args, use_list=None, **kwargs)
> --> 328     def __getitem__(self, idx): return self._get(idx) if is_indexer(idx) else L(self._get(idx), use_list=None)
>     329     def copy(self): return self._new(self.items.copy())
>     330 
> 
> /opt/conda/lib/python3.7/site-packages/fastcore/foundation.py in _get(self, i)
>     330 
>     331     def _get(self, i):
> --> 332         if is_indexer(i) or isinstance(i,slice): return getattr(self.items,'iloc',self.items)[i]
>     333         i = mask2idxs(i)
>     334         return (self.items.iloc[list(i)] if hasattr(self.items,'iloc')
> 
> IndexError: list index out of range

The first error states your loss function didn’t work. You will likely need a custom loss function if you haven’t done so. (Haven’t looked at your notebook)

You can test it and see what happens by passing in the output of your ys along with the output from your model. Not 100% sure on the second.

Yes defining an appropriate loss function did help for the first bit, thanks! I’ll have a look at the second one again, and post here if I find out what it is.