Torch.bincount behaves differently on CPU and GPU

username: HAL-42
cooked: <p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/4/c/4cc732d52daefac585ab9cf49097142eea6faa9f.png" data-download-href="https://discuss.pytorch.org/uploads/default/4cc732d52daefac585ab9cf49097142eea6faa9f" title="图片"><img src="https://discuss.pytorch.org/uploads/default/original/3X/4/c/4cc732d52daefac585ab9cf49097142eea6faa9f.png" alt="图片" data-base62-sha1="aXd4g80SUUNndHSh7bgoiYkVBn1" width="546" height="500" data-dominant-color="171616"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">图片</span><span class="informations">825×755 30.6 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div></p>
<p>It seems that for a tensor with dype=uint8, device=cuda, if there exits element=255, then torch.bincount will not count other bins than 255.<br>
The problem only occurs when tensor on GPU.</p>
<p>My pytorch version is 1.10.0.</p>

username: suraj.pt
cooked: <p>This error doesn’t occur in pytorch 1.11; can you try updating your version?</p>

username: HAL-42
cooked: <p><div class="lightbox-wrapper"><a class="lightbox" href="https://discuss.pytorch.org/uploads/default/original/3X/e/d/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587.jpeg" data-download-href="https://discuss.pytorch.org/uploads/default/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587" title="图片"><img src="https://discuss.pytorch.org/uploads/default/optimized/3X/e/d/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587_2_500x500.jpeg" alt="图片" data-base62-sha1="xRDGIySt3e0tv2GBduKmnd2pKT5" width="500" height="500" srcset="https://discuss.pytorch.org/uploads/default/optimized/3X/e/d/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587_2_500x500.jpeg, https://discuss.pytorch.org/uploads/default/original/3X/e/d/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587.jpeg 1.5x, https://discuss.pytorch.org/uploads/default/original/3X/e/d/ed57febb4ebe580d42df5dbf8bc6aeb2cf790587.jpeg 2x" data-dominant-color="34352E"><div class="meta"><svg class="fa d-icon d-icon-far-image svg-icon" aria-hidden="true"><use href="#far-image"></use></svg><span class="filename">图片</span><span class="informations">651×650 155 KB</span><svg class="fa d-icon d-icon-discourse-expand svg-icon" aria-hidden="true"><use href="#discourse-expand"></use></svg></div></a></div><br>
It seems this error still occur in pytorch 1.11.0，torch.cuda.version=11.3。</p>

username: tom
cooked: <p>I can see this on some post-1.11 cut dev branch. At first glance, it could be a bug with the CUDA implementation that shows with uint8 - for dtype int and long bincount seems to work as expected for me.</p>
<p>Best regards</p>
<p>Thomas</p>

username: tom
cooked: <p>Staring down the code a bit, this might be suspicious:</p>
<aside class="onebox githubblob" data-onebox-src="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L36">
  <header class="source">

      <a href="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L36" target="_blank" rel="noopener nofollow ugc">github.com</a>
  </header>

  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L36" target="_blank" rel="noopener nofollow ugc">pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L36</a></h4>



    <pre class="onebox">      <code class="lang-cu">
        <ol class="start lines" start="26" style="counter-reset: li-counter 25 ;">
            <li>       i += gridDim.x * blockDim.x)</li>
            <li>
            </li>
<li>/*</li>
            <li>  Memory types used for the 3 histogram implementations.</li>
            <li>  See `CUDA_tensor_histogram` below.</li>
            <li> */</li>
            <li>enum class CUDAHistogramMemoryType { SHARED, MULTI_BLOCK, GLOBAL };</li>
            <li>namespace {</li>
            <li>  template&lt;typename input_t, typename IndexType&gt;</li>
            <li>  __device__ static IndexType getBin(input_t bVal, input_t minvalue, input_t maxvalue, int64_t nbins) {</li>
            <li class="selected">    IndexType bin = (int)((bVal - minvalue) * nbins / (maxvalue - minvalue));</li>
            <li>    // (only applicable for histc)</li>
            <li>    // while each bin is inclusive at the lower end and exclusive at the higher, i.e. [start, end)</li>
            <li>    // the last bin is inclusive at both, i.e. [start, end], in order to include maxvalue if exists</li>
            <li>    // therefore when bin == nbins, adjust bin to the last bin</li>
            <li>    if (bin == nbins) bin -= 1;</li>
            <li>    return bin;</li>
            <li>  }</li>
            <li>}</li>
            <li>
            </li>
<li>/*</li>
        </ol>
      </code>
    </pre>



  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>I will check if that is the culprit and if so, I’ll send a PR.</p>
<p>Best regards</p>
<p>Thomas</p>
<p>Edited: This was not it. The computation is in int64 anyways.</p>

username: tom
cooked: <p>Now I found it.<br>
The maxvalue computed below has an overflow (we have nbins = 256 and so maxvalue will be 0 for uint8). Right now I’m checking whether the fix should be clamping to the numeric type max value or setting the maxvalue needs to be nbins - 1 and then I’ll send a PR.</p><aside class="onebox githubblob" data-onebox-src="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L316">
  <header class="source">

      <a href="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L316" target="_blank" rel="noopener nofollow ugc">github.com</a>
  </header>

  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L316" target="_blank" rel="noopener nofollow ugc">pytorch/pytorch/blob/621ff0f9735cd8c4c5d6becb291ad050c35e01c0/aten/src/ATen/native/cuda/SummaryOps.cu#L316</a></h4>



    <pre class="onebox">      <code class="lang-cu">
        <ol class="start lines" start="306" style="counter-reset: li-counter 305 ;">
            <li>  AT_ERROR("bincount only supports 1-d non-negative integral inputs.");</li>
            <li>}</li>
            <li>
            </li>
<li>bool has_weights = weights.defined();</li>
            <li>if (has_weights &amp;&amp; weights.size(0) != self.size(0)) {</li>
            <li>  AT_ERROR("input and weights should have the same length");</li>
            <li>}</li>
            <li>
            </li>
<li>const int64_t nbins = std::max(*self.max().cpu().data_ptr&lt;input_t&gt;() + (int64_t)1, minlength);</li>
            <li>const input_t minvalue = 0;</li>
            <li class="selected">const input_t maxvalue = nbins;</li>
            <li>// alloc output counter on GPU</li>
            <li>Tensor output;</li>
            <li>if (has_weights) {</li>
            <li>  output = native::zeros(</li>
            <li>      {nbins},</li>
            <li>      optTypeMetaToScalarType(weights.options().dtype_opt()),</li>
            <li>      weights.options().layout_opt(),</li>
            <li>      weights.options().device_opt(),</li>
            <li>      weights.options().pinned_memory_opt());</li>
            <li>  cuda::CUDA_tensor_histogram&lt;weights_t, input_t, true&gt;(</li>
        </ol>
      </code>
    </pre>



  </article>

  <div class="onebox-metadata">
    
    
  </div>

  <div style="clear: both"></div>
</aside>

<p>Best regards</p>
<p>Thomas</p>
<p>P.S.: Thank you <a class="mention" href="/u/hal-42">@HAL-42</a> for reporting this with repro. That is always very helpful.</p>
<p>P.P.S.: I sent <a href="https://github.com/pytorch/pytorch/pull/76979" class="inline-onebox" rel="noopener nofollow ugc">Fix bincount to use acc scalar for the bounds by t-vi · Pull Request #76979 · pytorch/pytorch · GitHub</a> , we will see how it goes.</p>