Delete all zero'ed rows from a tensor

username: sajastu
cooked: <p>Hello everyone!</p>
<p>I have a tensor, let’s say <code>A</code>, which contains zero rows. I mean rows with all zero elements. There are other rows with non-zero elements as well. I there any elegant way to remove all zero’ed rows? To shed a light on the question, suppose the following example.</p>
<pre><code class="lang-auto">A=
[ [ [0,0,0,0,0], [0,-0.4,0,-0.9,0], [0,-0.7,0.9,0.2,0], [0,0,0,0,0] ] ]
</code></pre>
<p>What I want to get (let’s say tensor B) is the following:</p>
<pre><code class="lang-auto">B=
[ [ [0,-0.4,0,-0.9,0], [0,-0.7,0.9,0.2,0] ] ]
</code></pre>

username: Sunshine352
cooked: <p>A = torch.Tensor([ [ [0,0,0,0,0], [0,-0.4,0,-0.9,0], [0,-0.7,0.9,0.2,0], [0,0,0,0,0] ] ])<br>
B = A[A.sum(dim=2) != 0]<br>
tensor([[ 0.0000, -0.4000,  0.0000, -0.9000,  0.0000],<br>
[ 0.0000, -0.7000,  0.9000,  0.2000,  0.0000]])</p>

username: KFrank
cooked: <p>Hi Sunny (and Sajad)!</p>
<aside class="quote no-group" data-username="Sunshine352" data-post="2" data-topic="54855" data-full="true">
<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/sunshine352/48/7667_2.png" class="avatar"> Sunshine352:</div>
<blockquote>
<p>A = torch.Tensor([ [ [0,0,0,0,0], [0,-0.4,0,-0.9,0], [0,-0.7,0.9,0.2,0], [0,0,0,0,0] ] ])<br>
B = A[A.sum(dim=2) != 0]<br>
tensor([[ 0.0000, -0.4000,  0.0000, -0.9000,  0.0000],<br>
[ 0.0000, -0.7000,  0.9000,  0.2000,  0.0000]])</p>
</blockquote>
</aside>
<p>That’s a nice solution.</p>
<p>Note, you should add an absolute-value in there to avoid deleting<br>
a non-zero row that sums to zero, such as <code>[1.0, -1.0, 0.0]</code>.</p>
<p>Best.</p>
<p>K. Frank</p>

username: Sunshine352
cooked: <p>Yeah, that’s right. I forgot it.</p>

username: Suraj
cooked: <p>Hi,</p>
<p>Thanks for the answer. Also, how can we get the list of indices corresponding to the “zero rows” ?<br>
Like for above mentioned question it would be like: [0,3]. Thanks!!</p>
<p>edit: I actually want to remove the corresponding columns as well for which rows were zero and removed. So if 1st and 3rd row in a 2D tensor is zero, I want to remove the 1st and 3rd column as well.</p>

username: KFrank
cooked: <p>Hi Suraj!</p>
<aside class="quote no-group" data-username="Suraj" data-post="5" data-topic="54855" data-full="true">
<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/suraj/48/28176_2.png" class="avatar"> Suraj:</div>
<blockquote>
<p>I actually want to remove the corresponding columns as well for which rows were zero and removed.</p>
</blockquote>
</aside>
<p>This question is a little simpler if the original tensor is square, that is,<br>
it has the same number or rows as columns.  (Not required, but you<br>
don’t have to fiddle around checking sizes.)</p>
<p>Here’s the most compact approach I could find, illustrated as a<br>
pytorch version 0.3.0 script:</p>
<pre data-code-wrap="python"><code class="lang-python">import torch
torch.__version__

# use a version of A that is square
# note, A has a leading size = 1 dimension

A = torch.FloatTensor ([ [ [0,0,0,0], [0,-0.4,0,-0.9], [0,-0.7,0.9,0.2], [0,0,0,0] ] ])
rows = (A.sum (dim = 2) != 0).squeeze()

# delete the rows and corresponding columns

C = A[torch.ger (rows, rows)].view ((1, rows.sum(), rows.sum()))
A
C

# get the non-zero-row indices

torch.arange (len (rows)).long()[rows]

# get the zero-row indices

torch.arange (len (rows)).long()[~rows]
</code></pre>
<p>Here is the output:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; import torch
&gt;&gt;&gt; torch.__version__
'0.3.0b0+591e73e'
&gt;&gt;&gt;
&gt;&gt;&gt; # use a version of A that is square
... # note, A has a leading size = 1 dimension
...
&gt;&gt;&gt; A = torch.FloatTensor ([ [ [0,0,0,0], [0,-0.4,0,-0.9], [0,-0.7,0.9,0.2], [0,0,0,0] ] ])
&gt;&gt;&gt; rows = (A.sum (dim = 2) != 0).squeeze()
&gt;&gt;&gt;
&gt;&gt;&gt; # delete the rows and corresponding columns
...
&gt;&gt;&gt; C = A[torch.ger (rows, rows)].view ((1, rows.sum(), rows.sum()))
&gt;&gt;&gt; A

(0 ,.,.) =
  0.0000  0.0000  0.0000  0.0000
  0.0000 -0.4000  0.0000 -0.9000
  0.0000 -0.7000  0.9000  0.2000
  0.0000  0.0000  0.0000  0.0000
[torch.FloatTensor of size 1x4x4]

&gt;&gt;&gt; C

(0 ,.,.) =
 -0.4000  0.0000
 -0.7000  0.9000
[torch.FloatTensor of size 1x2x2]

&gt;&gt;&gt;
&gt;&gt;&gt; # get the non-zero-row indices
...
&gt;&gt;&gt; torch.arange (len (rows)).long()[rows]

 1
 2
[torch.LongTensor of size 2]

&gt;&gt;&gt;
&gt;&gt;&gt; # get the zero-row indices
...
&gt;&gt;&gt; torch.arange (len (rows)).long()[~rows]

 0
 3
[torch.LongTensor of size 2]
</code></pre>
<aside class="quote no-group">
<blockquote>
<p>how can we get the list of indices corresponding to the “zero rows” ?</p>
</blockquote>
</aside>
<p>I would do it by indexing into a range, as illustrated in the above script.</p>
<p>Best.</p>
<p>K. Frank</p>

username: Suraj
cooked: <p>Thank you <a class="mention" href="/u/kfrank">@KFrank</a> for taking some time out to answer. I am getting an error while using torch.ger().<br>
Error message:</p>
<p><code> RuntimeError: _th_addr_out not supported on CPUType for Bool</code></p>
<p>Could it be because of pytorch version? I have the latest one installed.</p>
<p>I actually had a naive (or a long) approach to it:</p>
<pre><code class="lang-auto">import torch
A = torch.FloatTensor( [ [0,0,0,0], [0,-0.4,0,-0.9], [0,-0.7,0.9,0.2], [0,0,0,0] ] )
idx = []
idx_removed = []
for i in range(4):
    flag = 0
    for j in range(4):
        if A[i,j] != 0:
            flag = 1
    if flag == 1:
        idx.append(i)
    else:
        idx_removed.append(i)

count = len(idx_removed)

A = A[idx,:]
A = A[:,idx]
A
</code></pre>
<p>count gives the number of zero_rows and idx gives the rows and columns to keep and idx_removed are indices to be removed. and if you just want number of zero rows then:</p>
<p><code>count = np.count_nonzero(torch.sum(torch.abs(A),dim = -1)==0)</code></p>
<p>Sorry for the making it this long as I have switched from C++ to python not very long ago. Your approach is much more time efficient, right? Thanks!</p>

username: KFrank
cooked: <p>Hi Suraj!</p>
<aside class="quote no-group" data-username="Suraj" data-post="7" data-topic="54855" data-full="true">
<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/suraj/48/28176_2.png" class="avatar"> Suraj:</div>
<blockquote>
<p>I am getting an error while using torch.ger().<br>
Error message:</p>
<p><code> RuntimeError: _th_addr_out not supported on CPUType for Bool</code></p>
<p>Could it be because of pytorch version? I have the latest one installed.</p>
</blockquote>
</aside>
<p>I’m guessing, but yes, it is probably the pytorch version.  Unfortunately<br>
I don’t have an up-to-date version installed to test with.</p>
<p>For me (version 0.3.0) <code>rows</code>, as returned by<br>
<code>rows = (A.sum (dim = 2) != 0).squeeze()</code><br>
is a <code>ByteTensor</code>, while your error message mentions <code>Bool</code>.</p>
<p>From recollection, that is a post-0.3.0 change.</p>
<p>Anyway (guessing) try converting <code>rows</code> to a <code>LongTensor</code> before<br>
calling <code>ger()</code>, e.g.:</p>
<pre data-code-wrap="python"><code class="lang-python">C = A[torch.ger (rows.long(), rows.long())].view ((1, rows.sum(), rows.sum()))
</code></pre>
<aside class="quote no-group">
<blockquote>
<p>I actually had a naive (or a long) approach to it:</p>
<pre><code class="lang-auto">for i in range(4):
    ...
</code></pre>
<p>Your approach is much more time efficient, right?</p>
</blockquote>
</aside>
<p>As a general (and usually reliable) rule, doing things solely with<br>
pytorch tensor operations will be much more efficient than writing<br>
a python loop that loops over elements (or rows / columns / slices)<br>
of pytorch tensors.</p>
<p>If this happens inside of your training loop, for example, in your loss<br>
function where you want to backpropagate through the results of<br>
the loop computation, it can matter a lot.  If you’re doing it on a<br>
one-shot basis, for example, to prepare some data prior to training,<br>
you might not care.</p>
<p>Best.</p>
<p>K. Frank</p>