Hi!
I would like to build a model that uses the images of the prostate-cancer competition on kaggle: https://www.kaggle.com/c/prostate-cancer-grade-assessment/data
Here we get a tiff with the biopsy sample and an image-mask. The model should infere the cancer class on the isup_scale.
I have build a custom datablock (see this blog-post: https://asvcode.github.io/MedicalImaging/medical_imaging/prostate/kaggle/segmentation/2020/06/25/Selective-Mask.html):
def custom_img(fn):
fn = f'{train}/{fn.image_id}.tiff'
#print(fn)
try:
file = openslide.OpenSlide(str(fn))
except Exception as e:
print(e)
t = tensor(file.get_thumbnail(size=(255, 255)))
img_pil = PILImage.create(t)
return img_pil
def custom_selective_mask(fn):
fn = f'{mask}/{fn.image_id}_mask.tiff'
file = openslide.OpenSlide(str(fn))
t = tensor(file.get_thumbnail(size=(255, 255)))[:,:,0]
ts = show_selective(t, min_px=None, max_px=None)
return ts
blocks = (ImageBlock,
MaskBlock,
CategoryBlock)
getters = [
custom_img,
custom_selective_mask,
ColReader('isup_grade')
]
dblock = DataBlock(blocks=blocks,
getters=getters,
splitter=RandomSplitter(),
item_tfms=[Resize(224), ToTensor],
batch_tfms=[IntToFloatTensor, Normalize.from_stats(*imagenet_stats)])
dl = dblock.dataloaders(train_labels, bs=4)
dl.n_inp = 2
dl.show_batch(max_n=4)
Now I think I have to create a custom model with a forward function that accepts two items and stacks them into one tensor so that the model can use the image and the mask for learning.
class ProstateCancerModel(Module):
def __init__(self, encoder, head):
self.encoder, self.head = encoder, head
def forward(self, x1, x2):
ftrs = torch.cat([self.encoder(x1), self.encoder(x2)], dim=1)
return self.head(ftrs)
def loss_func(out, targ):
return CrossEntropyLossFlat()(out, targ.long())
def siamese_splitter(model):
return [params(model.encoder), params(model.head)]
encoder = create_body(resnet34, cut=-2)
head = create_head(512*2, 2, ps=0.5)
model = ProstateCancerModel(encoder, head)
Each item in the dataloader is now a tuple with the image, the image mask and the label:
dl.train_ds[0]
/content/prostate-cancer-data/train_images/002a4db09dad406c85505a00fb6f6144.tiff
(PILImage mode=RGB size=186x255,
PILMask mode=L size=186x255,
TensorCategory(0))
When I try to build the learner and fit for some epoches I get an error according a mismatch on dimensions…
learner = Learner(dl,
model,
loss_func=loss_func,
splitter=prostate_cancer_splitter,
metrics=accuracy
)
learner.freeze()
learner.fit_one_cycle(5)
/content/prostate-cancer-data/train_images/00412139e6b04d1e1cee8421f38f6e90.tiff
/content/prostate-cancer-data/train_images/0005f7aaab2800f6170c399693a96917.tiff
/content/prostate-cancer-data/train_images/0032bfa835ce0f43a92ae0bbab6871cb.tiff
/content/prostate-cancer-data/train_images/000920ad0b612851f8e01bcc880d9b3d.tiff
/content/prostate-cancer-data/train_images/003d4dd6bd61221ebc0bfb9350db333f.tiff
/content/prostate-cancer-data/train_images/001d865e65ef5d2579c190a0e0350d8f.tiff
/content/prostate-cancer-data/train_images/002a4db09dad406c85505a00fb6f6144.tiff
/content/prostate-cancer-data/train_images/004dd32d9cd167d9cc31c13b704498af.tiff
/content/prostate-cancer-data/train_images/004f6b3a66189b4e88b6a01ba19d7d31.tiff
/content/prostate-cancer-data/train_images/001c62abd11fa4b57bf7a6c603a11bb9.tiff
/content/prostate-cancer-data/train_images/0076bcb66e46fb485f5ba432b9a1fe8a.tiff
/content/prostate-cancer-data/train_images/003a91841da04a5a31f808fb5c21538a.tiff
/content/prostate-cancer-data/train_images/004391d48d58b18156f811087cd38abf.tiff
/content/prostate-cancer-data/train_images/006f4d8d3556dd21f6424202c2d294a9.tiff
/content/prostate-cancer-data/train_images/0018ae58b01bdadc8e347995b69f99aa.tiff
---------------------------------------------------------------------------
RuntimeError Traceback (most recent call last)
<ipython-input-233-c0f1748717fa> in <module>()
6 )
7 learner.freeze()
----> 8 learner.fit_one_cycle(5)
20 frames
/usr/local/lib/python3.7/dist-packages/torch/tensor.py in __torch_function__(cls, func, types, args, kwargs)
993
994 with _C.DisableTorchFunction():
--> 995 ret = func(*args, **kwargs)
996 return _convert(ret, cls)
997
RuntimeError: Expected 4-dimensional input for 4-dimensional weight [64, 3, 7, 7], but got 3-dimensional input of size [4, 224, 224] instead
So the input provided is a batch of size 4 with an image of 224x224 (imagenet resolution). I think this is correct. But I cannot figure out, where this expected input dimension comes from?