Is torch.poisson differentiable?

username: 111414
cooked: <p>I know that <code>torch.randn</code> is not differentiable, but we can use reparameterization technique to make the standard deviation differentiable:</p>
<pre><code class="lang-python">x = ...
noise = x * torch.randn_like(x)
</code></pre>
<p>Is <code>torch.poisson</code> differentiable? Or if there exists a way to make <code>torch.poisson</code> differentiable?</p>

username: AlphaBetaGamma96
cooked: <p>It has a grad function, therefore it’s differentiable.</p>
<pre><code class="lang-auto">x=torch.randn(100, 100, requires_grad=True).abs()
y=torch.poisson(x)
y.grad_fn #returns &lt;PoissonBackward0&gt; 
</code></pre>

username: KFrank
cooked: <p>Hi Bin!</p>
<aside class="quote no-group" data-username="111414" data-post="1" data-topic="153299" 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/111414/48/31166_2.png" class="avatar"> 111414:</div>
<blockquote>
<p>Is <code>torch.poisson</code> differentiable?</p>
</blockquote>
</aside>
<p>It depends on what you are actually asking.</p>
<p>The function <code>torch.poisson()</code> is not differentiable (even though it has<br>
a <code>grad_fn</code>).  There are two reasons for this:  First, <code>torch.poisson()</code><br>
returns a sample from the Poisson distribution, and pytorch does not<br>
support backpropagating through samples from distributions.  Second,<br>
Poisson samples are integer values (even though <code>torch.poisson()</code><br>
can return values of floating-point type).  So you can’t really differentiate<br>
a result that you can’t continuously vary away from its integer value.</p>
<p>If you try to backpropagate through <code>torch.poisson()</code>, you will get zeros<br>
for the gradients (even though its result appears to have a <code>grad_fn</code>):</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; import torch
&gt;&gt;&gt; torch.__version__
'1.11.0'
&gt;&gt;&gt; _ = torch.manual_seed (2022)
&gt;&gt;&gt; rate = torch.rand (100, 100, requires_grad = True)
&gt;&gt;&gt; samp = torch.poisson (rate)
&gt;&gt;&gt; samp.grad_fn
&lt;PoissonBackward0 object at 0x00000242A15A7B50&gt;
&gt;&gt;&gt; samp.sum().backward()
&gt;&gt;&gt; torch.all (rate.grad == 0.0)   # no useful gradients
tensor(True)
</code></pre>
<aside class="quote no-group">
<blockquote>
<p>Or if there exists a way to make <code>torch.poisson</code> differentiable?</p>
</blockquote>
</aside>
<p>On the other hand, it does make sense to differentiate the probability (or,<br>
for a continuous distribution, the probability density) of some sample value<br>
with respect to parameters of the distribution.</p>
<p>Consider:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; rate = torch.tensor ([3.5], requires_grad = True)
&gt;&gt;&gt; samp = torch.tensor ([4.0], requires_grad = True)
&gt;&gt;&gt; lp = torch.distributions.Poisson (rate).log_prob (samp)
&gt;&gt;&gt; lp
tensor([-1.6670], grad_fn=&lt;SubBackward0&gt;)
&gt;&gt;&gt; lp.backward()
&gt;&gt;&gt; rate.grad
tensor([0.1429])
</code></pre>
<p>Oddly enough, pytorch <em>does</em> return a non-trivial value for the <code>grad</code> of<br>
<code>samp</code>, even though <code>.log_prob (samp)</code> refuses to accept a non-integer<br>
value of <code>samp</code>:</p>
<pre><code class="lang-plaintext">&gt;&gt;&gt; samp.grad
tensor([-0.2534])
&gt;&gt;&gt; torch.distributions.Poisson (rate).log_prob (torch.tensor ([4.01]))
Traceback (most recent call last):
  File "&lt;stdin&gt;", line 1, in &lt;module&gt;
  File "&lt;path_to_pytorch_install&gt;\torch\distributions\poisson.py", line 61, in log_prob
    self._validate_sample(value)
  File "&lt;path_to_pytorch_install&gt;\torch\distributions\distribution.py", line 286, in _validate_sample
    raise ValueError(
ValueError: Expected value argument (Tensor of shape (1,)) to be within the support (IntegerGreaterThan(lower_bound=0)) of the distribution Poisson(rate: tensor([3.5000], requires_grad=True)), but found invalid values:
tensor([4.0100])
</code></pre>
<p>(It beats me what <code>samp.grad = tensor([-0.2534])</code> means or where it<br>
comes from.)</p>
<p>Best.</p>
<p>K. Frank</p>

username: 111414
cooked: <p>I am very grateful for the detailed response from <a class="mention" href="/u/kfrank">@KFrank</a>.<br>
Based on your given tips, I may understand that the original <code>torch.poisson</code> is not differentiable (or the <code>grad</code> will always be zeros).<br>
And there is an indirect way to optimize the Poisson parameters by using <code>torch.distributions.Poisson</code> and <code>.log_prob</code>.<br>
These are really helpful for me and have addressed my problem.</p>