Hello Ryan!



 RyanPatterson:

My images are grayscale between 0-1.0 with shape (batchsize, #classes, image height, image width). My masks are binary with 0 for background(I dont care about) and 1 for the crack sections. My first question is can I get away with using only 1 class or do I need to use 2? I’m not sure exactly how to calculate accuracy.


You’re basically on the right track.  Let me make some suggestions
(but, note, you can usually do more-or-less the same thing in a
couple of different ways).
You are working on a binary segmentation problem.  (This is a
binary classifier, where you classify individual pixels.)  You could
treat this as the two-class case of a general multi-class problem,
but you’re marginally better off treating this as a binary problem.
So don’t explicitly use two classes.
The images you input to your model should have shape
[batchsize, height, width] – no class dimension,
because your input images don’t know anything about class.
The output of your model – which will be one of the inputs to
your loss function – should have the same shape – also no
class dimension (because were implementing this as a binary
problem).  Your masks (sometimes called labels or targets) – the
other input to your loss function – should also have the same
shape, again no class dimension (the class information is contained
in the binary values of the mask pixels).  And even though (in your
case) binary, your masks should be FloatTensors.
You should use BCEWithLogitsLoss.  (NLLLoss is reasonable,
but is for the multi-class problem, and you’re better off going the
pure binary route.)  The output of your model should be raw-score
logits that run from -inf to inf, so you shouldn’t pass them
through a non-linearity such as sigmoid().


I’m not sure exactly how to calculate accuracy.


Conceptually, you convert a prediction logit to a probability – to be
understood as the (predicted) probability of a pixel being in the
“1” (crack) class – by passing it though a sigmoid().  You would
typically convert a prediction probability to a yes-no prediction by
thresholding the probability – p > 0.5 means class-“1”.
Because sigmoid() maps a logit of 0.0 to a probability of 0.5,
you can simply compare your logits (the output of your model)
with a threshold of 0.0.  These are your yes-no predictions for
your pixels, and your accuracy is typically taken to be the fraction
of pixels for which these prediction are correct, i.e., are equal to
your mask values.
One last comment:  It may be the case that you have many more
“background” pixels than “crack” pixels.  If so, you might want to
experiment with using a class weight in your loss function.  (Look at
the pos_weight argument to BCEWithLogitsLoss constructor.)
But you should try things first with an unweighted loss function just
to see how well the plain-vanilla approach.
Best.
K. Frank