Integer convolution on GPU

vaferdolosa: <p>I’m using pytorch to perform some image processing computations (no AI involved).</p>
<p>Especially I’m trying to perform integer convolutions on GPU, excepting a significant boost in performance in comparison to float32 (is it really the case? I observed some strange behaviors like float16 convolutions being slower than float32, so I’m not sure anymore …).</p>
<p>However when I want to do this, I got various error like that  type not supported or CUDNN_STATUS_BAD_PARAM</p>
<p>I imagine that integer convolution must be implemented somewhere for quantization computation, but I wasn’t able to find it.<br>
Is there a way to efficiently perform a convolution between int16 tensors with PyTorch? (And will it be really much faster than float32 convolution in practice? )</p>
<p>Thank you for your help !</p>

ptrblck: <p>Integer inputs and parameters shouldn’t be supported in native <code>nn.Modules</code> and you should see an error during the transformation as:</p>
<pre><code class="lang-python">conv.to(torch.int16)
&gt; TypeError: nn.Module.to only accepts floating point or complex dtypes, but got desired dtype=torch.int16
</code></pre>
<p>If you use integer inputs this error will be raised:</p>
<pre><code class="lang-python">x = x.to(torch.int16)
out = conv(x)
&gt; RuntimeError: Input type (short int) and bias type (float) should be the same
</code></pre>
<p>Could you describe how you got the cuDNN error and post a minimal and executable code snippet to reproduce the issue, please?</p>

vaferdolosa: <p>Thank you for your answer.</p>
<p>Here is my code:</p>
<pre><code class="lang-auto">import torch.nn.functional as F

dtype = torch.int32

ref = torch.randint(0,256,(1,100,100), dtype=dtype).to(device)
tocompare = torch.randint(0,256,(30,1,100,100), dtype=dtype).to(device)

result = F.conv2d(ref, tocompare, padding=30)
</code></pre>
<p><em>( to give some context, it allows me to find an image in a batch of images, one of which is the reference image but translated )</em></p>
<p>which gives me the following error with “dtype=torch.int32” but works fine with “dtype=torch.float32”</p>
<pre><code class="lang-auto">File "home/user/.local/lib/python3.8/site-packages/torch/utils/_device.py", line 62, in __torch_function__
    return func(*args, **kwargs)
RuntimeError: CUDNN_BACKEND_OPERATION: cudnnFinalize Failed cudnn_status: CUDNN_STATUS_BAD_PARAM
</code></pre>
<p>Is there a way to accelerate 2d convolutions on integer, or I’m stuck with the float32 convolution? In this case, how does quantized convolution work? Is there a way to hack it to perform my convolution more efficiently?</p>
<p>Thank you</p>

ptrblck: <p>Thanks for the code. The error message is indeed a bit misleading and would fail with a disallowed <code>dtype</code> message as seen in my code snippet using modules.</p>
<aside class="quote no-group" data-username="vaferdolosa" data-post="3" data-topic="179845">
<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/vaferdolosa/48/60471_2.png" class="avatar"> vaferdolosa:</div>
<blockquote>
<p>Is there a way to accelerate 2d convolutions on integer, or I’m stuck with the float32 convolution? In this case, how does quantized convolution work? Is there a way to hack it to perform my convolution more efficiently?</p>
</blockquote>
</aside>
<p>For inference you could try to use TorchTRT which could quantize the model and speed it up.<br>
I don’t know if another backend already uses integer ops for performance reasons.</p>

HDCharles: <p>The main way to speed up integer math on gpu is probably using torch.compile along with triton. We’re taking this avenue ourselves (the quantization/ao team) for implementing quantization on GPU for certain application areas. I’m not sure if the int8 convolution kernels are exposed as of now but the torch._int_mm kernel is exposed and you can theoretically convert a convolution into a matmul.</p>

vaferdolosa: <p>Thank you both of you for these relevant answers.<br>
I will look into TorchRT and Triton. It seems it could be good solutions for my need.</p>
<p>Converting the convolution into matrix multiplication is also a great idea, I’m just wondering if building the equivalent matrix won’t slow down the operation.</p>
<blockquote>
<p>torch._int_mm kernel is exposed</p>
</blockquote>
<p>On my side I wasn’t able to perform an int matrix multiplication, both @ and .mm  with torch.int gives:</p>
<pre><code class="lang-auto">RuntimeError: "addmm_cuda" not implemented for 'Int'
</code></pre>
<p>And “torch._int_mm” isn’t recognized neither. (I tested with torch ‘2.0.0a0+8aa34602.nv23.03’)<br>
Maybe this is only valid in a Triton context or something similar?</p>
<p>Thank you!</p>

HDCharles: <p>i’m not sure about that error see this test for an example usage:</p>
<aside class="onebox githubblob" data-onebox-src="https://github.com/pytorch/pytorch/blob/47d31364d724fd34b1050c1d91e252f24deed425/test/test_linalg.py#LL5613C16-L5613C16">
  <header class="source">

      <a href="https://github.com/pytorch/pytorch/blob/47d31364d724fd34b1050c1d91e252f24deed425/test/test_linalg.py#LL5613C16-L5613C16" target="_blank" rel="noopener nofollow ugc">github.com</a>
  </header>

  <article class="onebox-body">
    <h4><a href="https://github.com/pytorch/pytorch/blob/47d31364d724fd34b1050c1d91e252f24deed425/test/test_linalg.py#LL5613C16-L5613C16" target="_blank" rel="noopener nofollow ugc">pytorch/pytorch/blob/47d31364d724fd34b1050c1d91e252f24deed425/test/test_linalg.py#LL5613C16-L5613C16</a></h4>



    <pre class="onebox"><code class="lang-py">
      <ol class="start lines" start="5613" style="counter-reset: li-counter 5612 ;">
          <li>c_int32 = torch._int_mm(a_int8, b_int8)</li>
      </ol>
    </code></pre>



  </article>

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

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

<p>otherwise, yes, converting to a matrix multiplication may be slow, i haven’t tested it personally. Also note: _int_mm is for int8 tensors (which is what we use for quantization) not int16 so it should be a ~4x speedup.</p>
<p>fp16 should be ~2x faster than fp32, thats what a lot of people are using on gpu, not sure whether your shapes are in a weird range where the fp16 kernel is slower than fp32 but that shouldn’t be true in general, at least for big shapes.</p>
<p>overall though, i think GPUs aren’t really setup for integer math at the moment, we’re currently making our first forray into native quantization on GPU right now and we haven’t even looked at conv so it may just be bad timing, if you hop forward in time 1 year I expect i’d have a better solution for you.</p>
<p>You could also create a pytorch feature request to expose a basic 2d conv op on gpu, similar to torch._int_mm</p>

vaferdolosa: <p>I was testing with int16, but I retry with int8 and got same error (with ‘Char’ instead of ‘Int’)</p>
<p>Yes I was surprised to have better performances with float32 vs float16  (I work on an AGX ORIN). It is  possible that my shapes are weird (kernels are something like (500,1,50,50) )</p>
<p>Ok I understand your point with GPUs. Do your think adding a basic 2d int conv op like torch.__int__mm will result in a  significant gain in performances, more precisely my question is: are issues with int on GPU about hardware not designed for that or only software support?</p>
<p>Thank you !</p>

HDCharles: <p>I’ve seen an error like that, it occured when my triton version didn’t match my version of pytorch. If you use nightlies for both that may fix it.</p>
<p>More importantly IDK how you are calling the addmm_cuda kernel, because torch._int_mm doesn’t call that kernel as far as I know.</p>
<p>note: torch._int_mm only works for 2 by 2 matrices so your shape you mention may require reshaping first.</p>
<p>About performance, yes, torch._int_mm is like 2x faster than fp16 which in our benchmarks is 2x faster than fp32. Its mostly a software issue, until torch._int_mm was exposed, you couldn’t do matmul’s quickly either.</p>

vaferdolosa: <p>Currently I haven’t yet tried triton, it was just a pure pytorch test.</p>
<p>addmm_cuda was raised when trying to perform an int matmul in pure pytorch</p>
<p>I take note of the compatible matrix size, however my torch version  (‘2.0.0a0+8aa34602.nv23.03’) doesn’t even seem to have torch._int_mm: <code>AttributeError: module 'torch' has no attribute '_int_mm'</code></p>
<p>Thank you for the performances metrics, that’s really interesting. That means I could expect up to a x4 in performances in comparison to my current f32 implementation (and in addition I would save time by skipping int16-&gt;f32-&gt;int16 convertions which seems also to add some latency).</p>
<p>Exposing a basic 2d int conv on gpu would be a great improvement for me (but I imagine my use case is quite atypical, I’m not even doing AI but simple algorithms in int16)</p>
<p>Thank you !</p>