v923z / micropython-ulab

a numpy-like fast vector module for micropython, circuitpython, and their derivatives
https://micropython-ulab.readthedocs.io/en/latest
MIT License
403 stars 111 forks source link

[BUG] indexing with Booleans leads to crash #672

Open v923z opened 2 months ago

v923z commented 2 months ago

As mentioned in https://github.com/v923z/micropython-ulab/issues/671, the following code leads to a crash:

filtered_boxes = np_boxes[np_boxes[:, 4] > 0.0]

@kwagyeman

v923z commented 1 month ago

Wouldn't it be better to use https://numpy.org/doc/stable/reference/generated/numpy.select.html for this? My reasoning is that first, that would lead to a cleaner implementation, second, it would be easier to customise the firmware. Excluding a function/method is more meaningful than excluding a sub-feature of a feature.

kwagyeman commented 1 month ago

Sounds fine. Just need a way to do it.

kwagyeman commented 1 month ago

Question, does where() work?

def yolov5_vectorized(model, input, output):
    out = output[0]
    ib, ih, iw, ic = model.input_shape[0]
    ob, ow, oc = model.output_shape[0]
    if ob != 1:
        raise ValueError("Expected model output batch to be 1!")
    if oc < 6:
        raise ValueError("Expected model output channels to be >= 6")

    # Extract relevant output slices
    scores = out[0, :, 4]
    coords = out[0, :, :4]

    # Filter indices where score > 0.5
    valid_indices = np.where(scores > 0.5)[0]

    # Compute bounding box coordinates
    cx = coords[valid_indices, 0]
    cy = coords[valid_indices, 1]
    cw = coords[valid_indices, 2] * 0.5
    ch = coords[valid_indices, 3] * 0.5

    xmin = (cx - cw) * iw
    ymin = (cy - ch) * ih
    xmax = (cx + cw) * iw
    ymax = (cy + ch) * ih

    # Compute label index
    labels = out[0, valid_indices, 5:]
    label_index = np.argmax(labels, axis=1)

    # Create bounding boxes
    nms = NMS(iw, ih, input[0].roi)
    for i in range(len(valid_indices)):
        nms.add_bounding_box(xmin[i], ymin[i], xmax[i], ymax[i], scores[valid_indices[i]], label_index[i])

    boxes = nms.get_bounding_boxes()
    return boxes

I could use it to accomplish my goal of being able to select indices. ChatGPT wrote the code above, though, and it might have made a mistake regarding how to select columns.

v923z commented 1 month ago

Yes, where should work, if you enabled it in ulab.h.

kwagyeman commented 1 month ago

Having issues with this stuff still:

a = np.array(range(36)).reshape((6, 6))

i = np.nonzero(np.asarray(a[:, 4] > 15))

print(a[i])

Doesn't work. Not sure why. I get a IndexError: indices must be integers, slices, or Boolean lists.

And then this says:

a = np.array(range(36)).reshape((6, 6))

i = np.where(a[:, 4] > 15, 1, 0)

print(i)

NotImplementedError: operation is implemented for 1D Boolean arrays only which it mentions in the docs. Could this restriction be removed? Need this to process tensor outputs.

It's not clear how to move forward without writing a for loop. Trying to stay vectorized.

v923z commented 1 month ago

NotImplementedError: operation is implemented for 1D Boolean arrays only which it mentions in the docs. Could this restriction be removed? Need this to process tensor outputs.

It's not trivial (and this is why I didn't implement it in the first place), but I'll try to find a way.