Coder Social home page Coder Social logo

mmgalushka / hungarian-loss Goto Github PK

View Code? Open in Web Editor NEW
9.0 2.0 0.0 268 KB

Computes loss between two sets of entities using the optimal assignment based on the Hungarian algorithm.

License: MIT License

Shell 4.75% Python 95.25%
python deep-learning object-detection tensorflow computer-vision object-classification object-segmentation

hungarian-loss's Introduction

Hungarian Loss

hungarian-loss Logo

Continuous Integration Status Code Coverage Percentage Codacy Badge Code style: black Python Badge Tensorflow Badge Project License

When you train a computer vision model detecting multiple objects within an image, you need to define a strategy for computing the loss between ground y_true truth and predicted y_pred sets of bounding boxes. This strategy needs to provide consistent matching between these two sets. The function implemented in this project uses a Hungarian algorithm to determine the optimal assignments between these two sets of bounding boxes and uses it for computing the loss.

Installing

Install and update using pip:

~$ pip install hungarian-loss

Note, this package does not have extra dependencies except Tensorflow ๐ŸŽ‰.

How to use it

The following example shows how to compute loss for the model head predicting bounding boxes.

from hungarian_loss import hungarian_loss

model = ...

losses = {"...": ..., "bbox": hungarian_loss}
lossWeights = {"...": ..., "bbox": 1}

model.compile(optimizer='adam', loss=losses, loss_weights=lossWeights)

Where to use it

Let's assume you are working on a deep learning model detecting multiple objects on an image. For simplicity of this example, let's consider, that our model intends to detect just two objects of kittens (see example below).

Use-case Example

Our model predicts 2 bounding boxes where it "thinks" kittens are located. We need to compute the difference between true and predicted bounding boxes to update model weights via back-propagation. But how to know which predicted boxes belong to which true boxes? Without the optimal assignment algorithm which consistently assigns the predicted boxes to the true boxes, we will not be able to successfully train our model.

The loss function implemented in this project can help you. Intuitively you can see that predicted BBox 1 is close to the true BBox 1 and likewise predicted BBox 2 is close to the true BBox 2. the cost of assigning these pairs would be minimal compared to any other combinations. As you can see, this is a classical assignment problem. You can solve this problem using the Hungarian Algorithm. Its Python implementation can be found here. It is also used by DERT Facebook End-to-End Object Detection with Transformers model. However, if you wish to use pure Tensor-based implementation this library is for you.

How it works

To give you more insights into this implementation we will review a hypothetical example. Let define true-bounding boxes for objects T1 and T2:

Object Bounding boxes
T1 1., 2., 3., 4.
T2 5., 6., 7., 8.

Do the same for the predicted boxes P1 and P2:

Object Bounding boxes
P1 1., 1., 1., 1.
P2 2., 2., 2., 2.

et's compute the Euclidean distances between all combinations of True and Predicted bounding boxes:

P1 P2
T1 3.7416575 2.449489
T2 11.224972 9.273619

This algorithm will compute the assignment mask first:

P1 P2
T1 1 0
T2 0 1

And then compute the final error:

loss = (3.7416575 + 9.273619) / 2 = 6.50763825

In contrast, if we would use the different assignment:

loss = (2.449489 + 11.224972) / 2 = 6.8372305

As you can see the error for the optimal assignment is smaller compared to the other solution(s).

Contributing

For information on how to set up a development environment and how to make a contribution to Hungarian Loss, see the contributing guidelines.

Links

hungarian-loss's People

Contributors

mmgalushka avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

hungarian-loss's Issues

'float' object is not callable when using HungarianLoss class.

Got the following error, when trying to use HungarianLoss class:

Traceback (most recent call last):
  File "xxx.py", line 127, in <module>
    model.fit(
  File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/utils/traceback_utils.py", line 67, in error_handler
    raise e.with_traceback(filtered_tb) from None
  File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/tensorflow/python/framework/func_graph.py", line 1147, in autograph_handler
    raise e.ag_error_metadata.to_exception(e)
TypeError: in user code:

    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/training.py", line 1021, in train_function  *
        return step_function(self, iterator)
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/training.py", line 1010, in step_function  **
        outputs = model.distribute_strategy.run(run_step, args=(data,))
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/training.py", line 1000, in run_step  **
        outputs = model.train_step(data)
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/training.py", line 860, in train_step
        loss = self.compute_loss(x, y, y_pred, sample_weight)
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/training.py", line 918, in compute_loss
        return self.compiled_loss(
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/engine/compile_utils.py", line 201, in __call__
        loss_value = loss_obj(y_t, y_p, sample_weight=sw)
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/keras/losses.py", line 141, in __call__
        losses = call_fn(y_true, y_pred)
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/hungarian_loss/loss.py", line 170, in call  **
        tf.map_fn(
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/hungarian_loss/loss.py", line 171, in <lambda>  **
        lambda x: self.__compute_sample_loss(x[0], x[1]),
    File "/home/mykola/Projects/squids/.venv/lib/python3.8/site-packages/hungarian_loss/loss.py", line 149, in __compute_sample_loss
        tf.reduce_mean(loss_fn(v_true_reordered, v_pred_reordered))

    TypeError: 'float' object is not callable

The code sample, which leads to the above error:

import tensorflow as tf
from hungarian_loss import HungarianLoss

model = Model(...)

model.compile(
    optimizer=tf.keras.optimizers.Adam(),
    loss=HungarianLoss(
        [4,4],
        slice_losses_fn = [
            tf.keras.losses.mean_absolute_error,
            tf.keras.losses.categorical_crossentropy
        ]
    )
)

model.fit(
    ds_train,
    steps_per_epoch = train_steps_per_epoch,
    epochs=10,
    validation_data=ds_val,
    validation_steps = val_steps_per_epoch,
    verbose=1
)

select_optimal_assignment_mask(reduce_matrix()) is behaving not as expected

Hello! Thank you for your work.

Before using your tensorflow implementation of hungarian algorithm I ran several tests and noticed that on some inputs it does not work as expected (I was comparing it to scipy.optimize.linear_sum_assignment).

For instance, the following code

from hungarian_loss.steps import (
    reduce_matrix,
    select_optimal_assignment_mask,
)
import tensorflow as tf
import numpy as np

cost = np.array(
    [[0., 9., 7., 5.],
     [4., 2., 0., 9.],
     [7., 5., 4., 2.],
     [0., 9., 7., 5.]]
)
cost = tf.cast(tf.constant(cost), tf.float32)
select_optimal_assignment_mask(reduce_matrix(cost))

returns

<tf.Tensor: shape=(4, 4), dtype=bool, numpy=
array([[ True, False, False, False],
       [False, False,  True, False],
       [False,  True, False, False],
       [False, False, False, False]])>

As you can see, it matches only 3 pairs instead of 4. The last row and last column do not have any True value.

Do you have any ideas, why this is happenning and how to fix this? Or am I using it incorrectly?

Add badges

Adds a set of badges summarizing the status of this project.

Unknown best slice_weights in advance.

When we compute the total loss which combines losses for every part we need to apply weighs. These weights allow balancing losses from different slices (considering the different nature of each slice). However, in advance, the loss value for each slice is unknown, which makes it awkward to set it in advance. The possible solution would be to determine the balancing weights automatically.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.