Expending PyTorch with lower than 8-bit Quantization

lijunzh: <p>I am interested in using PyTorch for 1-bit neural network training. It seems to me that pytorch now only supports <code>dtype=qint8</code>. I am wondering if there is an good guide for PyTorch dtype system and how to expanding it.</p>
<p>Thanks.</p>

jerryzh168: <p>cc <a class="mention" href="/u/raghuramank100">@raghuramank100</a> has a diff out, but it’s not landed yet: <a href="https://github.com/pytorch/pytorch/pull/33743" rel="nofollow noopener">https://github.com/pytorch/pytorch/pull/33743</a></p>

lijunzh: <p>Thanks <a class="mention" href="/u/jerryzh168">@jerryzh168</a>, that’s good info to keep an eye on.</p>

lijunzh: <p><a href="https://github.com/pytorch/pytorch/pull/33743" rel="nofollow noopener">https://github.com/pytorch/pytorch/pull/33743 </a> give a nice touch on the sub-8-bit quantization. However, if I want to do some 1-bit quantization which quantizes the feature map and weight matrices into {-1, 1}.  This may requires further changes in the <code>qscheme</code>. I am guessing that will require me add some PyTorch intrinsics in ATen? Or there is a better way to accomendate that need?</p>
<p>In any case, I am looking forward to see <a href="https://github.com/pytorch/pytorch/pull/33743" rel="nofollow noopener">33743</a> land soon.</p>

jerryzh168: <aside class="quote no-group" data-username="lijunzh" data-post="4" data-topic="80343">
<div class="title">
<div class="quote-controls"></div>
<img loading="lazy" alt="" width="24" height="24" src="https://discuss.pytorch.org/letter_avatar_proxy/v4/letter/l/ac91a4/48.png" class="avatar"> lijunzh:</div>
<blockquote>
<p><a href="https://github.com/pytorch/pytorch/pull/33743" rel="noopener nofollow ugc">https://github.com/pytorch/pytorch/pull/33743 </a> give a nice touch on the sub-8-bit quantization. However, if I want to do some 1-bit quantization which quantizes the feature map and weight matrices into {-1, 1}. This may requires further changes in the <code>qscheme</code> . I am guessing that will require me add some PyTorch intrinsics in ATen? Or there is a better way to accomendate that need?</p>
</blockquote>
</aside>
<p>right, if it is {-1, 1} it is not probably not affine quantization, what would you quantize 0 into?<br>
I think you’ll probably need to extend qscheme and implement a new quantizer(<a href="https://codebrowser.bddppq.com/pytorch/pytorch/aten/src/ATen/quantized/Quantizer.h.html" class="inline-onebox" rel="noopener nofollow ugc">Quantizer.h source code [pytorch/aten/src/ATen/quantized/Quantizer.h] - Woboq Code Browser</a>) to support this.</p>

lijunzh: <blockquote>
<p>if it is {-1, 1} it is not probably not affine quantization, what would you quantize 0 into?</p>
</blockquote>
<p>I am trying to follow the <a href="https://arxiv.org/abs/1603.05279" rel="noopener nofollow ugc">XNOR-Net</a> paper and its variant which quantizes the filter weights <strong>W</strong> into <strong>B</strong> such that <strong>W</strong> approximates a<strong>B</strong> where a is a real valued scalar. Thus, by the equation (4) in that paper, <strong>B</strong>i = +1 if <strong>W</strong>i &gt;= 0 and <strong>B</strong>i = -1 if <strong>W</strong>i &lt; 0.</p>
<p>I am looking at the ATen code, it seems to be that if we want to add the support such binary quantization scheme, we will have to recompile PyTorch locally in order to have the new ATen library takes effect. Is there any way I can do it using the official PyTorch distribution without re-compilation?</p>

jerryzh168: <p>yeah, that is correct, you’ll need to implement a new quantization scheme, and probably adding a new quantize function <a href="https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/native_functions.yaml#L3809" rel="nofollow noopener">https://github.com/pytorch/pytorch/blob/master/aten/src/ATen/native/native_functions.yaml#L3809</a> etc. we don’t have a good way to simulate this in current codebase I think. since this level of support is targeted at production.</p>
<p>However, if you just want to simulate the accuracy of the model in training, you might get away with less complete support in core, for example, just add a new quantization scheme and add support for it in the fake quantize module: <a href="https://github.com/pytorch/pytorch/blob/master/torch/quantization/fake_quantize.py#L92" rel="nofollow noopener">https://github.com/pytorch/pytorch/blob/master/torch/quantization/fake_quantize.py#L92</a>.</p>
<p>But anyways you’ll probably need to add a new quantization scheme <a href="https://github.com/pytorch/pytorch/blob/master/c10/core/QScheme.h" rel="nofollow noopener">https://github.com/pytorch/pytorch/blob/master/c10/core/QScheme.h</a></p>

lijunzh: <p>Thanks for the detailed explanation. This is very helpful.</p>
<p>I mainly target at evaluating models in 1-bit precision with QAT, so I guess the second approach is good enough (for now). It seems that I still will need touch the Aten/c10 code and recompile it locally. If so, is this something the PyTorch team interested to merge upstream in the future (assuming my code meets the quality requirement)?</p>
<p>On a related note, Nvidia’s new <a href="https://devblogs.nvidia.com/nvidia-ampere-architecture-in-depth/" rel="noopener nofollow ugc">A100 architecture</a> will support binary (1-bit) precision.</p>
<blockquote>
<p>Acceleration for all data types, including FP16, BF16, TF32, FP64, INT8, INT4, and Binary</p>
</blockquote>
<p>This is not too far away from the production. Details can also be found in their <a href="https://www.nvidia.com/content/dam/en-zz/Solutions/Data-Center/nvidia-ampere-architecture-whitepaper.pdf" rel="noopener nofollow ugc">white paper</a>. It feel like an interesting direction for PyTorch community to explore and will be meaningful if we can support in the long-run.</p>

jerryzh168: <p>yeah low precision quantization is definitely something we want to pursue, but it may not need extra quantization schemes to support them, although we’ll need new data type support. for example, we can have per tensor affine quantization(existing quantization scheme) with Int4(new data type).</p>
<p>In the case of 1-bit precision to {1, -1}, we also need a new quantization scheme since it is not affine quantization. if the integer values are consecutive, e.g. {-1, 0, 1}, {0, 1}, I think we should be able to represent it with per tensor affine quantization and a new INT1/INT2 data type.</p>

lijunzh: <p>I agree with the comment of sub-8-bit quantization. We should be able to support 2-7 bit using the existing infrastructure with some new data types INT2-7.</p>
<p>In the case of 1-bit (binary), you can represent {-1, 1} in {0, 1} by assigning -1 to 0. In fact, that’s what will be implemented in hardware. However, that means you will replace multiplication by XNOR. This change results in a separate set of operators/functionals/modules need to be overload for binary network. From math point of view, I would like to see BNN implemented in this way (which exactly match the hardware). However, it is a lot of work and hard to be maintained (separately from all other NN modules). Frankly, an engineer will argue that there is no significant benefit of doing so. I feel like a new data type BINT1 for {-1, 1} (to be different from INT1 for {0, 1}) is a better choice.</p>
<p>I will try to experiment with this idea and submit issue/PR in the coming months.</p>

frank_huang: <p>Hi, Lijun.</p>
<p>How’s PyTorch sub-8 bit quantization going? I have not seen any official tutorial about this.</p>

christophezei: <p>Can someone explain for me please how dtype qint8 works? I am not able to understand how we are representing a tensor that contains many fp32 values (weight, scale_f and zero_p) but on a 8 bits representation and gain in memory</p>

Vasiliy_Kuznetsov: <p>Feel free to check out <a href="https://pytorch.org/blog/quantization-in-practice/#mapping-function" class="inline-onebox" rel="noopener nofollow ugc">Practical Quantization in PyTorch | PyTorch</a> for an explanation of the math behind the <code>torch.qint8</code> format.</p>