Some safe indexing for tensor?

username: aliutkus
cooked: <p>Hi !</p>
<p>let’s say I have a tensor <code>v</code> of shape <code>(dim_m,dim_n,1,dim_q)</code>. The tensor is super big.</p>
<p>For some reason, I want to support accessing it with <code>v[m,n,p,q]</code> where <code>p</code> can actually go beyond <code>0</code>.</p>
<p>In my application, the desired behaviour is to basically ignore <code>p</code>, so that I should return <code>v[m,n,0,q]</code>.<br>
This means that indexes out of bounds should clamp to the latest available entry on that dimension.</p>
<ul>
<li>An easy solution would of course be to duplicate <code>v</code> along the p dimension, but I don’t want to do that for speed and also because <code>v</code> is a huge tensor</li>
<li>I can’t modify the fact that I will ask for some <code>p</code> that go beyond 0. (I isolated the core question, the fact that I want to index there is a consequence of using some complicated <code>torch.gather</code> stuff)</li>
</ul>
<p>In essence, I want some “safe indexing” tensor. does that exist ? Can I overload the <code>torch.Tensor</code> class to accomplish this without breaking everything ?</p>

username: Matias_Vasquez
cooked: <p>As you said, you could ignore <code>p</code>.</p>
<aside class="quote no-group" data-username="aliutkus" data-post="1" data-topic="151010">
<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/aliutkus/48/5600_2.png" class="avatar"> aliutkus:</div>
<blockquote>
<p>the desired behaviour is to basically ignore <code>p</code></p>
</blockquote>
</aside>
<p>But if you want to clamp your inputs you could use <code>torch.clamp</code> <a href="https://pytorch.org/docs/stable/generated/torch.clamp.html" rel="noopener nofollow ugc">documentation</a></p>
<pre data-code-wrap="python"><code class="lang-python"># Example
dim_m = 10
dim_n = 20
p = 0
dim_q = 30

min_ = torch.zeros(4)
max_ = torch.tensor([dim_m, dim_n, p, dim_q])

inp = torch.randint(-1, 50, (4,), dtype=torch.float)

print(inp)

clamped_inp = torch.clamp(inp, min_, max_)
print(clamped_inp)

# Output:
# inp:     tensor([ 9., 48., 15., 33.])
# clamped: tensor([ 9., 20.,  0., 30.])
</code></pre>

username: aliutkus
cooked: <p>Thanks for your answer, but this doesn’t answer my question, because I basically cannot influence <em>with which indices</em> the tensor <code>v</code> will be accessed. This means that v <em>will</em> be accessed with your <code>inp</code> variable. I need to address my problem elsewhere, e.g. by deriving a <code>SafeAccessTensor</code> class</p>

username: Matias_Vasquez
cooked: <p>Well I would limit the access to the user with a method.<br>
Inside it check if the input is valid and clamp it if not.</p>
<p>Something like:</p>
<pre><code class="lang-python">def get_v(idx_m, idx_n, idx_p, idx_q):
    # clamp inputs
    # select v with valid indices
    return v
</code></pre>
<p>But maybe someone else has a better solution that actually solves your problem.</p>

username: aliutkus
cooked: <p>thanks again a million for the time spent for me =)</p>
<p>Unfortunately, I can’t do this thing because the indexing is done inside another function that is internal to torch (<code>torch.gather</code> in this case)</p>

username: Andrei_Cristea
cooked: <p>I believe just subclassing torch.Tensor might do the trick. Something like this:</p>
<pre><code class="lang-auto"># suppose you want to "virtually expand" dim 2
class MyTensor(torch.Tensor):
    def __getitem__(self, index):
        index = list(index)
        index[2] = 0
        return super().__getitem__(tuple(index))

tensor = torch.randn(3, 4, 1, 6)
mytensor = MyTensor(tensor)

print(mytensor[0, 0, 0, 0], mytensor[0, 0, 1, 0], mytensor[0, 0, 2, 0])  # works and is identical, as desired
print(mytensor[0, 0, 0, 0], mytensor[1, 0, 0, 0], mytensor[2, 0, 0, 0])  # is different

Output:
tensor(0.1178) tensor(0.1178) tensor(0.1178)
tensor(0.1178) tensor(1.3803) tensor(-1.2770)
</code></pre>
<p>This mock class will fail if you want to also access the tensor via a slice, such as mytensor[0, 0, :, 0]. You have to fiddle around and make that work by adding a bit of logic around:</p>
<pre><code class="lang-auto">if type(index[2]) == slice:
</code></pre>
<p>But it shouldn’t be too bad!</p>

username: aliutkus
cooked: <p>This indeed answers the question, although it turns out that the function I am using is apparently implemented in a way that <code>__getitem__</code> is not called. Still, this requires a specific question and is out of the scope of that one, which you answered nicely. Thanks for this !</p>