How to compute the IoU of a Tensor and a List

Onur_Ozbek: <p>I have the following custom loss function for an SSD model. Its not fully implemented yet:</p>
<pre><code class="lang-auto">class SSDLoss(torch.nn.Module):
    def __init__(self, device=torch.device("cpu"), background_ratio=6):
        super(SSDLoss, self).__init__()
        self.device = device
        self.background_ratio = background_ratio

    def forward(self, predictions_list, targets, anchor_boxes, num_classes=2):
        # convert bboxes to ssd outputs
        # compare

        true_targets = targets_to_bboxes(anchor_boxes, targets, device=self.device)
        
        print('true_targets: ', true_targets)
        print('predictions_list: ', predictions_list)
        print('true_targets size: ', len(true_targets))
        print('predictions_list size: ', len(predictions_list))
        
        loss = 0

        return loss, true_targets
</code></pre>
<p><code>true_targets</code> (Torch tensor) are my ground truth bounding boxes and <code>prediction_list</code> are my predicted bounding boxes (Python list). These are the outputs of the 4 print statements.</p>
<p>This is <code>true_targets</code> and its shape:</p>
<pre><code class="lang-auto">true_targets:  tensor([[[0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [2., 2., 2.,  ..., 2., 2., 2.]],

        [[0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [2., 2., 2.,  ..., 2., 2., 2.]],

        [[0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [2., 2., 2.,  ..., 2., 2., 2.]],

        [[0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [0., 0., 0.,  ..., 0., 0., 0.],
         [2., 2., 2.,  ..., 2., 2., 2.]]])

torch.Size([4, 5, 9040])
</code></pre>
<p>This is <code>predictions_list</code> and its length:</p>
<pre><code class="lang-auto">predictions_list:  [tensor([[[[ 9.9442e-02,  3.3226e-01,  1.2670e-01,  ...,  9.9745e-02,
            2.7174e-01,  1.0590e-01],
          [ 2.3663e-01,  3.1417e-01,  1.3010e-01,  ...,  1.9857e-02,
           -6.4091e-02,  3.8148e-01],
          [ 3.0299e-01,  3.2582e-01,  2.4724e-01,  ...,  2.2392e-01,
            6.4675e-02,  7.2070e-03],
          ...,
          [ 3.5731e-03,  2.8286e-01,  7.7916e-01,  ..., -9.8466e-02,
            2.4779e-01, -2.9651e-01],
          [ 2.7502e-01,  1.5084e-01,  3.5121e-01,  ...,  2.8136e-01,
           -4.1414e-03,  2.6915e-01],
          [ 1.5553e-01,  1.6558e-02,  2.2879e-01,  ...,  4.3227e-01,
            6.3580e-02,  4.4533e-02]],

         [[ 1.7918e-01, -1.2231e-01,  1.1551e-02,  ..., -4.5121e-02,
           -1.4862e-01, -2.5158e-01],
          [-2.8866e-02,  1.9356e-01,  2.1619e-01,  ..., -2.0484e-01,
           -4.7227e-01, -2.5157e-01],
          [ 2.7363e-02, -3.8109e-02,  1.8184e-02,  ..., -2.9303e-01,
           -5.7727e-01, -3.6232e-01],
          
          ...,
          [ 6.8932e-01,  5.6035e-01,  4.3400e-02,  ..., -1.2163e-01,
           -8.7152e-02,  2.3896e-01],
          [ 3.3151e-01,  3.1092e-01,  3.2296e-01,  ...,  5.2497e-02,
           -2.1015e-01, -2.9203e-01],
          [ 8.8831e-02,  1.5703e-01,  2.1559e-01,  ..., -5.8313e-02,
           -8.0042e-02, -1.4649e-01]]]], grad_fn=&lt;ConvolutionBackward0&gt;)]

predictions_list:  2
</code></pre>
<p>I tried to comvert <code>predictions_list</code> to a torch tensor like this <code>torch.as_tensor(predictions_list)</code> but it gave me this output: <code>only one element tensors can be converted to Python scalars</code></p>
<p>I want to calculate the IOU between the ground truths and predictions. How can I go about it?</p>

srishti-git1110: <p>Hi,<br>
Can you please see if the following thread helps?</p><aside class="quote quote-modified" data-post="1" data-topic="161515">
  <div class="title">
    <div class="quote-controls"></div>
    <img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/n/e68b1a/48.png" class="avatar">
    <a href="https://discuss.pytorch.org/t/cant-convert-cuda-0-device-type-tensor-to-numpy-use-tensor-cpu-to-copy-the-tensor-to-host-memory-first-and-list-object-has-no-attribute-cpu/161515">"can't convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first." and "list object has no attribute cpu"</a> <a class="badge-category__wrapper " href="/c/vision/5"><span data-category-id="5" data-drop-close="true" class="badge-category " title="Topics related to either pytorch/vision or vision research related topics"><span class="badge-category__name">vision</span></span></a>
  </div>
  <blockquote>
    Hello guys, 

I have one of the common issues of type conversion “can’t convert cuda:0 device type tensor to numpy. Use Tensor.cpu() to copy the tensor to host memory first.” 
So, I tried to solve like the answer comment " .cpu().numpy() ".
But unfortunately, another issue “list object has no attribute cpu.”
By trying to solve with “.cpu().detach().numpy()”, I got the error “list object has no attribute cpu”.
I also tried one of the related suggestions in this forum like “new_tensor = torch.tens…
  </blockquote>
</aside>


Onur_Ozbek: <p>Hi Srishti</p>
<p>Your answers talk about converting list of tensors to numpy array. I am trying to do an IoU so doesn’t it make more sense for me to convert my list to a torch tensor?</p>

srishti-git1110: <p>I was thinking on some different lines, but yes best is to convert the list <code>predictions_list</code> into a tensor. For this, I find <code>torch.cat</code> a nice way.</p>
<p>Like this -</p>
<pre><code class="lang-auto"># creating a list of tensors
import torch
list_of_tensors = []
x = torch.tensor([1.0, 2, 3])
list_of_tensors.append(x)

x = torch.tensor([4.0, 5, 6])
list_of_tensors.append(x)

list_of_tensors
</code></pre>
<p>out -</p>
<pre><code class="lang-auto">[tensor([1., 2., 3.]), tensor([4., 5., 6.])]
</code></pre>
<p>Converting to tensor-</p>
<pre><code class="lang-auto">list_of_tensors = [t.unsqueeze(0) for t in list_of_tensors] # unsqueeze to add an extra dim 
t = torch.cat(list_of_tensors, dim=0)
print(t)
</code></pre>
<p>out -</p>
<pre><code class="lang-auto">tensor([[1., 2., 3.],
        [4., 5., 6.]])
</code></pre>
<p>Please let me know if this doesn’t help you.</p>

Onur_Ozbek: <p>I don’t quite understand the necessity of this:</p>
<pre><code class="lang-auto"># creating a list of tensors
import torch
list_of_tensors = []
x = torch.tensor([1.0, 2, 3])
list_of_tensors.append(x)

x = torch.tensor([4.0, 5, 6])
list_of_tensors.append(x)

list_of_tensors
</code></pre>

srishti-git1110: <p>That’s just a list of tensors I created to demonstrate the usage.</p>
<p>For your use, it would hence be -</p>
<pre><code class="lang-auto">predictions_list = [t.unsqueeze(0) for t in predictions_list]
t = torch.cat(predictions_list, dim=0)
</code></pre>
<p>Does this produce any error?</p>

Onur_Ozbek: <aside class="quote no-group" data-username="srishti-git1110" data-post="4" data-topic="161898">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/srishti-git1110/48/52515_2.png" class="avatar"> srishti-git1110:</div>
<blockquote>
<p><code>torch.cat(list_of_tensors, dim=0)</code></p>
</blockquote>
</aside>
<p>This is what I got<br>
<code>Sizes of tensors must match except in dimension 0. Expected size 45 but got size 23 for tensor number 1 in the list.</code></p>

srishti-git1110: <p>Which probably means the two tensors in <code>predictions_list</code> aren’t of same size. Is that it?</p>
<p>If yes, it requires a bit complicated workaround than if it’s not.<br>
See-</p><aside class="quote quote-modified" data-post="7" data-topic="59949">
  <div class="title">
    <div class="quote-controls"></div>
    <img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/user_avatar/discuss.pytorch.org/nikronic/48/71873_2.png" class="avatar">
    <a href="https://discuss.pytorch.org/t/best-way-to-convert-a-list-to-a-tensor/59949/7">Best way to convert a list to a tensor?</a> 
  </div>
  <blockquote>
    Hi, 
I think <a href="https://pytorch.org/docs/stable/generated/torch.tensor.html" rel="noopener nofollow ugc">torch.tensor — PyTorch 1.7.0 documentation</a> and <a href="https://pytorch.org/docs/stable/generated/torch.as_tensor.html" rel="noopener nofollow ugc">torch.as_tensor — PyTorch 1.7.0 documentation</a> have explained the difference clearly but in summary, torch.tensor always copies the data but torch.as_tensor tries to avoid that! In both cases, they don’t accept sequence of tensors. 
The more intuitive way is stacking in a given dimension which you can find here: <a href="https://discuss.pytorch.org/t/how-to-turn-a-list-of-tensor-to-tensor/8868">How to turn a list of tensor to tensor? - PyTorch Forums</a> 
The problem with your approach is that you convert your tensors to nu…
  </blockquote>
</aside>


Onur_Ozbek: <p><code>true_targets.shape: torch.Size([4, 5, 9040])</code><br>
<code>prediction_list.length: predictions_list:  2</code></p>

srishti-git1110: <p>What about the sizes of two tensors in predictions_list?</p>

Onur_Ozbek: <p><code>print(len(predictions_list[0])): 4</code></p>
<p>Both tensors have a size of 4.</p>

srishti-git1110: <p>Not the length exactly, the sizes need to match.<br>
Please share the output of -</p>
<pre><code class="lang-auto">print(predictions_list[0].shape)
print(predictions_list[1].shape)
</code></pre>

naychelynn: <p>Hi Ms. Srishti,</p>
<p>now I can solve it !<br>
Thanks for your supportive suggestion.</p>