Search code examples
c++torchlibtorch

What's the equivalent of np.delete in libtorch?


It seems we don't have an np.delete equivalent in libtorch yet, so how can we emulate its behavior? For example I'm trying to rewrite the following bit of code in libtorch:

ids = np.delete( ids, np.concatenate([[last], np.where(overlap > overlap_threshold)[0]] ) )

How should I go about this? I thought about slicing, but I'm not sure if there are implications involved that I'm not aware of. This is what I came up with:

neg = torch.where(overlap < overlap_threshold)[0]
ids = ids[neg].clone()

libtorch:

auto neg = torch::where(overlap <over_threshold)[0];
ids.index_put_({Slice()}, ids.index({neg}));
//or simply
ids = ids.index({neg}).clone();

And this is an example demo to test out their result is the same:

x1 = np.asarray([125.,152., 155., 155., 202.])
y1 = np.asarray( [52., 72., 92., 95., 95.])
x2 = np.asarray( [145., 172., 175., 175., 222.])
y2 = np.asarray( [ 72.,  92., 112., 115., 115.])
score = np.asarray([0.60711509, 0.63444906, 0.85604602, 0.60021192, 0.70115328])
area = (x2 - x1 + 1.0) * (y2 - y1 + 1.0)
ids = np.argsort(score)
overlap_threshold = 0.5
mode = 'union'
while len(ids) > 0:
    # grab index of the largest value
    last = len(ids) - 1
    i = ids[last]

    # left top corner of intersection boxes
    ix1 = np.maximum(x1[i], x1[ids[:last]])
    iy1 = np.maximum(y1[i], y1[ids[:last]])

    # right bottom corner of intersection boxes
    ix2 = np.minimum(x2[i], x2[ids[:last]])
    iy2 = np.minimum(y2[i], y2[ids[:last]])

    # width and height of intersection boxes
    w = np.maximum(0.0, ix2 - ix1 + 1.0)
    h = np.maximum(0.0, iy2 - iy1 + 1.0)

    # intersections' areas
    inter = w * h
    if mode == 'min':
        overlap = inter / np.minimum(area[i], area[ids[:last]])
    elif mode == 'union':
        # intersection over union (IoU)
        overlap = inter / (area[i] + area[ids[:last]] - inter)

    # delete all boxes where overlap is too big
    # ids = np.delete(ids,np.concatenate([[last], np.where(overlap > overlap_threshold)[0]]))
    neg = np.where(overlap <= overlap_threshold)[0]
    ids = ids[neg]
    print(f'ids: {ids}')

And here is the cpp counter part in libtorch:

void test5()
{
    auto x1 = torch::tensor({ 125., 152., 155., 155., 202. });
    auto y1 = torch::tensor({ 52., 72., 92., 95., 95. });
    auto x2 = torch::tensor({ 145., 172., 175., 175., 222. });
    auto y2 = torch::tensor({ 72., 92., 112., 115., 115. });
    auto score = torch::tensor({ 0.60711509, 0.63444906, 0.85604602, 0.60021192, 0.70115328 });
    auto area = (x2 - x1 + 1.0) * (y2 - y1 + 1.0);
    auto ids = torch::argsort(score);
    auto overlap_threshold = 0.5;
    auto mode = "union";
    while (ids.sizes()[0] > 0)
    {
        //# grab index of the largest value
        auto last = ids.sizes()[0] - 1;
        auto i = ids[last];

        //# left top corner of intersection boxes
        auto ix1 = torch::max(x1[i], x1.index({ ids.index({ Slice(None,last) }) }));
        auto iy1 = torch::max(y1[i], y1.index({ ids.index({ Slice(None,last) }) }));

        //# right bottom corner of intersection boxes
        auto ix2 = torch::min(x2[i], x2.index({ ids.index({Slice(None,last)}) }));
        auto iy2 = torch::min(y2[i], y2.index({ ids.index({Slice(None,last)}) }));

        //# width and height of intersection boxes
        auto w = torch::max(torch::tensor(0.0), ix2 - ix1 + 1.0);
        auto h = torch::max(torch::tensor(0.0), iy2 - iy1 + 1.0);

        //# intersections' areas
        auto inter = w * h;
        torch::Tensor overlap;
        if (mode == "min")
        {
            overlap = inter / torch::min(area[i], area.index({ ids.index({Slice(None,last)}) }));
        }
        else if (mode == "union")
        { //# intersection over union (IoU)
            overlap = inter / (area[i] + area.index({ ids.index({Slice(None,last)}) }) - inter);
        }
        //# delete all boxes where overlap is too big
        //# ids = np.delete(ids, np.concatenate([[last], np.where(overlap > overlap_threshold)[0]] ))
        auto neg = torch::where(overlap < overlap_threshold)[0];
        ids = ids.index({ neg });
        std::cout << "ids: " << ids << std::endl;
    }
}

Both of them print the same output, so is there something that I'm missing here or this is actually the reasonable way of implementing delete in libtorch?

What other possibly more efficient ways do I have to implement/emulate np.delete()?


Solution

  • It seems this is the reasonable way of doing it as pointed out in the comments. That is to reverse the condition and only filter out based on the new condition.
    I also would like to fix a slight issue in my original post. the correct form that would be equivalent to the Pythons :

    ids = np.delete(ids, np.concatenate([[last], np.where(overlap > overlap_threshold)[0]] ))
    

    would be :

    auto neg = torch::where(overlap <= overlap_threshold)[0];
    ids = ids.index({ neg });
    

    mind the <=!