How can I create this tensor in PyTorch without using Numpy?

username: ProGamerGov
cooked: <p>I’d like to be able to create this tensor without using Numpy, but I can’t find the PyTorch equivalent to Numpy’s <a href="https://numpy.org/doc/1.18/reference/generated/numpy.fft.fftfreq.html" rel="nofollow noopener"><code>fft.fftfreq</code></a>:</p>
<pre><code class="lang-auto">import numpy as np	
def get_fft_scale(h, w, decay_power=.75):
    d=.5**.5 # set center frequency scale to 1
    fy = np.fft.fftfreq(h,d=d)[:,None]
    if w % 2 == 1:
        fx = np.fft.fftfreq(w,d=d)[: w // 2 + 2]
    else:
        fx = np.fft.fftfreq(w,d=d)[: w // 2 + 1]        
    freqs = (fx*fx + fy*fy) ** decay_power
    scale = 1.0 / np.maximum(freqs, 1.0 / (max(w, h)*d))
    scale = torch.Tensor(scale).float()[None,None,...,None]
    return scale
</code></pre>

username: albanD
cooked: <p>Hi,</p>
<p>What is the difference between this and a histogram functions?</p>

username: ProGamerGov
cooked: <p>So, I guess the question is how to generate the initial tensors then?</p>
<pre><code class="lang-auto">&gt;&gt;&gt; import numpy as np
&gt;&gt;&gt; h = 8
&gt;&gt;&gt; d = .5**.5
&gt;&gt;&gt; fy = np.fft.fftfreq(h,d=d)
&gt;&gt;&gt; fy
array([ 0.        ,  0.1767767 ,  0.35355339,  0.53033009, -0.70710678,
       -0.53033009, -0.35355339, -0.1767767 ])
</code></pre>

username: ProGamerGov
cooked: <p>I’m not quite sure. I’m using this tensor for spatial decorrelation of a tensor.</p>

username: albanD
cooked: <p>Given this and the definition in their doc, it feels like you can implement it with a simple arange function no?</p>

username: ProGamerGov
cooked: <p>It looks like I can recreate it with the following function, using <code>torch.arange</code> twice:</p>
<pre><code class="lang-auto">def create_freq_tensor(size, cf=.5**.5):
    step=(cf/(size/2))
    end = (step * size)/2
    return torch.cat([torch.arange(0,end=end,step=step), torch.arange(-cf, end=0, step=step)])
</code></pre>

username: albanD
cooked: <p>Nice!<br>
That looks good !</p>

username: ProGamerGov
cooked: <p>And then I guess this is the full function:</p>
<pre><code class="lang-auto">def create_freq_tensor(size, cf=.5**.5, device='cpu'):
    step=(cf/(size/2))
    end = (step * size)/2
    return torch.cat([torch.arange(0, end=end, step=step, device=device), torch.arange(-cf, end=0, step=step, device=device)])

def get_fft_scale(h, w, decay_power=.75, device='cpu'):
    d=.5**.5
    fy = create_freq_tensor(h, device=device)[:,None]
    if w % 2 == 1:
        wadd = 2
    else:
        wadd = 1
    fx = create_freq_tensor(w, device=device)[: w // 2 + wadd]        
    freqs = (fx*fx + fy*fy) ** decay_power
    scale = 1 / torch.max(freqs, torch.full_like(freqs, 1.0 / (max(w, h)*d)))
    return scale[None,None,...,None]
</code></pre>
<p>Is there a way I could do it better?</p>

username: albanD
cooked: <p>Given that you take only the first half of the output of <code>create_freq_tensor</code>, you might just want a single arange call. and you can remove the cat as well no?</p>

username: ProGamerGov
cooked: <p>Yes, I can just remove the cat as well and instead do this (<a href="https://github.com/numpy/numpy/blob/v1.18.1/numpy/fft/helper.py#L165-L172" rel="nofollow noopener">based on the NumPy code</a>):</p>
<pre><code class="lang-auto"># NumPy fft.fftfreq in PyTorch
def pytorch_fftfreq(n, d=1.0, device='cpu'):		
    results = torch.empty(n, device=device)
    s = (n-1) // 2 + 1
    results[:s] = torch.arange(0, s, device=device)
    results[s:] = torch.arange(-(n//2), 0, device=device)
    return results * (1.0 / (n * d))
</code></pre>