Gustavo
Gustavo

Reputation: 716

Keras returns wrong value for sum

I have this code to understand how Jaccard Index works and I am trying to implement it as a Keras custom metric, but the return of this function is wrong and I have no idea why (I am new to Keras btw).

This function creates a rectangular area to test intersections:

def block(start, width=20, heigth=10, length=60):
    block = np.zeros((1, heigth, length))
    block[:, :, start:(start + width)] = 1
    return block.astype('uint8')

If I get a block(10) and a block(20) there should be two 10x20 blocks with a 10x10 area of intersection so the union must be 2*(10*20) - 10*10 which is confirmed by this Numpy line:

np.sum(((block(10) + block(20)) > 0).astype('uint8'))

But when I try to use this Keras function:

def test(a, b):
    return K.sum(K.cast((a + b) > 0, dtype='uint8'))

The result is 44 when I call it with K.eval(test(block(10), block(20)))

EDIT (new test):

def test(a, b):
    return K.sum(a), K.sum(b), K.sum(a) + K.sum(b)

[K.eval(elem) for elem in test(block(10), block(20))]

This is the result: [200, 200, 144]

What am I doing wrong to get this result?

Upvotes: 0

Views: 101

Answers (1)

user2653663
user2653663

Reputation: 2948

The dtype of the Keras sum is inferred from the object that is summed over, so in this case the sum will be of type uint8. Your result is 300. uint8 can take 256 different values, and 300 - 44 = 256. If you take a closer look on your python code:

blocks = block(10) + block(20) # dtype='uint8'
mask = (blocks > 0) # dtype=bool
mask_as_uint = mask.astype('uint8') # dtype='uint8', which is an unnescessary conversion
np.sum(mask_as_uint) # dtype='uint64

So your result is of type uint64, while you ask Keras to give you a result in uint8. In fact the following gives 44 as an answer as well:

np.int8(300)

In short, switch to a bigger dtype for the sum or do the operations in an order manually where uint8 doesn't have shortcomings.

Upvotes: 1

Related Questions