Hi,
I am working on a multiclass segmentation task, and I’ve been stuck trying to implement loss for IoU metrics.
I am using fastai v1.0.11.
I am running into the following error when putting my loss function (which is supposed to return 1-iou) in my learner :
learner = Learner(bunch, custom_model, loss_func=IOU(), metrics=[iou], callback_fns=ShowGraph)
learner.fit_one_cycle(1)
<ipython-input-127-158e79851ed2> in <module>()
----> 1 learner.fit_one_cycle(1)
~/anaconda3/lib/python3.7/site-packages/fastai/train.py in fit_one_cycle(learn, cyc_len, max_lr, moms, div_factor, pct_start, wd, callbacks, **kwargs)
17 callbacks.append(OneCycleScheduler(learn, max_lr, moms=moms, div_factor=div_factor,
18 pct_start=pct_start, **kwargs))
---> 19 learn.fit(cyc_len, max_lr, wd=wd, callbacks=callbacks)
20
21 def lr_find(learn:Learner, start_lr:Floats=1e-7, end_lr:Floats=10, num_it:int=100, **kwargs:Any):
~/anaconda3/lib/python3.7/site-packages/fastai/basic_train.py in fit(self, epochs, lr, wd, callbacks)
134 callbacks = [cb(self) for cb in self.callback_fns] + listify(callbacks)
135 fit(epochs, self.model, self.loss_func, opt=self.opt, data=self.data, metrics=self.metrics,
--> 136 callbacks=self.callbacks+callbacks)
137
138 def create_opt(self, lr:Floats, wd:Floats=0.)->None:
~/anaconda3/lib/python3.7/site-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
86 except Exception as e:
87 exception = e
---> 88 raise e
89 finally: cb_handler.on_train_end(exception)
90
~/anaconda3/lib/python3.7/site-packages/fastai/basic_train.py in fit(epochs, model, loss_func, opt, data, callbacks, metrics)
76 for xb,yb in progress_bar(data.train_dl, parent=pbar):
77 xb, yb = cb_handler.on_batch_begin(xb, yb)
---> 78 loss = loss_batch(model, xb, yb, loss_func, opt, cb_handler)[0]
79 if cb_handler.on_batch_end(loss): break
80
~/anaconda3/lib/python3.7/site-packages/fastai/basic_train.py in loss_batch(model, xb, yb, loss_func, opt, cb_handler)
23 if opt is not None:
24 loss = cb_handler.on_backward_begin(loss)
---> 25 loss.backward()
26 cb_handler.on_backward_end()
27 opt.step()
~/anaconda3/lib/python3.7/site-packages/torch/tensor.py in backward(self, gradient, retain_graph, create_graph)
100 products. Defaults to ``False``.
101 """
--> 102 torch.autograd.backward(self, gradient, retain_graph, create_graph)
103
104 def register_hook(self, hook):
~/anaconda3/lib/python3.7/site-packages/torch/autograd/__init__.py in backward(tensors, grad_tensors, retain_graph, create_graph, grad_variables)
88 Variable._execution_engine.run_backward(
89 tensors, grad_tensors, retain_graph, create_graph,
---> 90 allow_unreachable=True) # allow_unreachable flag
91
92
RuntimeError: element 0 of tensors does not require grad and does not have a grad_fn
Here is my implementation of IOU loss class. and iou metrics (not the most efficient, but it works)
class IOU(torch.nn.Module):
def __init__(self, classes = np.array(range(13))):
super(IOU,self).__init__()
self.classes = classes
def forward(self, input, target):
return (1- iou(input, target, self.classes))
#iou metrics
def tp_fp_fn_1class(pred, gt):
"""
:param pred : binary tensor of predictions for that class of shape image shape
:param gt: ground truth tensor
:returns : true positive, false positive, false negative rate for that class
"""
tp = (pred*gt).sum(dim=0).sum().float()
fp = ((pred - gt) > 0).sum(dim=0).sum().float()
fn = ((gt - pred) > 0).sum(dim=0).sum().float()
return tp, fp, fn
def iou_1class(tp,fp,fn):
return(tp/(tp+fp+fn))
def iou(input:Tensor, targs:Tensor, classes = np.array(range(13)),ignore_class = [0]):
preds_ = input.argmax(dim = 1)
num_sample = input.shape[0]
ious = np.zeros((num_sample,len(classes)))
classes_ = np.array(classes.copy())
if ignore_class != None:
for i in ignore_class:
classes_ = np.delete(classes_, np.where(classes_ == i)[0])
num_class = len(classes_)
for i in range(num_sample):
pred = preds_[i]
gt = targs[i]
for c in classes_:
tp, fp, fn = tp_fp_fn_1class((pred==c).float(), (gt==c).float())
ious[i][c] = iou_1class(tp,fp,fn)
if np.isnan(ious[i][c]):
ious[i][c]= 0
avg_im = np.sum(ious, axis = 0)/num_sample
avg_iou = np.sum(avg_im)/num_class
return tensor(avg_iou)
```
Thank you very much for your help!