For the moment, I’ll keep the learn.export() function from the original code I have after calling learn.save(). If after showing the current code to my professors they tell me it’s not necessary to use learn.export() I’ll remove it.
Alright.
I agree, now all the posts you made that have helped me solve all the errors have a like.
To clarify it, I want to communicate to @idraja & @muellerzr who I asked for help on this topic, that the problems for which I contacted them have been solved by applying the solutions @matdmiller proposed to me.
Hi @matdmiller,
I’ve been advancing the project for which I created this topic. To put you in context my project is about the analysis of lungs in X-ray images to detect COVID-19.
I’ve trained a lungs detection model.
Now I need to apply inference to predict the bounding boxes on images of a different dataset.
When I tried to execute the function “model.predict” I got an error related to the “custom_bb_pad” function. It’s a function you suggested me to implement to fix an issue I was having related to a mismatch of shapes between the CNN output (shape 1x8) and the target bounding boxes (shape 2x4).
I debugged the function “custom_bb_pad” to check what it was doing but I didn’t notice any change on the shape of the “bbox” parameter at the end of the debugging.
As I didn’t notice “custom_bb_pad” was necessary I commented it. After running the notebook I’ve been able to train the lungs detection model and to get the same metrics results (IoU) as when “custom_bb_pad” was uncommented. Plus, if I run model.predict() I no longer have an error.
I’d like to know why should I need to use “custom_bb_pad”.
Next, I show you the code you sent me to make matchable the shapes of the CNN model and the target bounding boxes.
Thank you.
# Cell
class NoLabelBBoxLabeler(Transform):
""" Bounding box labeler with no label """
def setups(self, x): noop
def decode (self, x, **kwargs):
self.bbox,self.lbls = None,None
return self._call('decodes', x, **kwargs)
def decodes(self, x:TensorBBox):
self.bbox = x
return self.bbox if self.lbls is None else LabeledBBox(self.bbox, self.lbls)
'''
def custom_bb_pad(samples, pad_idx=0):
"Function that collect `samples` of bboxes and adds padding with `pad_idx`."
# 'samples' is a list that contains a tuple with 2 elements: a TensorImage & a TensorBBox. TensorBBox size is (2,4)
# TensorImage size is [3, width, height]
max_len = max([len(s[1]) for s in samples]) # s[1] is a TensorBBox. max_len equals to 2 (number of bboxes associated to a TensorBBox)
def _f(img,bbox): # img is a TensorImage, bbox is a TensorBBox
bbox = torch.cat([bbox,bbox.new_zeros(max_len-bbox.shape[0], 4)])
return img,bbox
return [_f(*s) for s in samples] # _f function receives a TensorImage as first parameter (img) and a TensorBBox as second parameter (bbox)
CustomBboxBlock = TransformBlock(type_tfms=TensorBBox.create,
item_tfms=[PointScaler, NoLabelBBoxLabeler], dls_kwargs = {'before_batch': custom_bb_pad})
'''
CustomBboxBlock = TransformBlock(type_tfms=TensorBBox.create,
item_tfms=[PointScaler, NoLabelBBoxLabeler])
class BBoxReshape(DisplayedTransform):
"Normalize/denorm batch of `TensorImage`"
parameters,order = L(),100
def __init__(self):
noop
def setups(self, dl:DataLoader):
noop
def encodes(self, x:TensorBBox): return torch.reshape(x,(x.shape[0],8)) # x.shape original is (64,2,4) and it gets converted to (64,8)
def decodes(self, x:TensorBBox): return torch.reshape(x,(x.shape[0],2,4)) # x.shape original is (64,8) and it gets converted to (64,2,4)```
The reshaping was moved here.
Because you always have exactly 2 bounding boxes, you probably don’t.
Sorry for the delay.
Alright.
From the experiments I’ve done I noticed I don’t need to use the “custom_bb_pad” function.