-
Notifications
You must be signed in to change notification settings - Fork 409
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
No longer make ExponentPrecisionType and XnorPrecisionType inherit from IntegerPrecisionType #845
Changes from all commits
d5d97d9
3fff994
53ae873
73d5740
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ | |
higher-dimensional tensors, which are defined as arrays or FIFO streams in the generated code. | ||
""" | ||
|
||
import re | ||
from enum import Enum | ||
|
||
import numpy as np | ||
|
@@ -46,7 +45,7 @@ class BinaryQuantizer(Quantizer): | |
|
||
def __init__(self, bits=2): | ||
if bits == 1: | ||
hls_type = IntegerPrecisionType(width=1, signed=False) | ||
hls_type = XnorPrecisionType() | ||
elif bits == 2: | ||
hls_type = IntegerPrecisionType(width=2) | ||
else: | ||
|
@@ -221,6 +220,10 @@ def __init__(self, width, signed): | |
self.width = width | ||
self.signed = signed | ||
|
||
def __eq__(self, other): | ||
eq = self.width == other.width | ||
eq = eq and self.signed == other.signed | ||
|
||
|
||
class IntegerPrecisionType(PrecisionType): | ||
"""Arbitrary precision integer data type. | ||
|
@@ -311,16 +314,21 @@ def __eq__(self, other): | |
return eq | ||
|
||
|
||
class XnorPrecisionType(IntegerPrecisionType): | ||
class XnorPrecisionType(PrecisionType): | ||
""" | ||
Convenience class to differentiate 'regular' integers from BNN Xnor ones | ||
""" | ||
|
||
def __init__(self): | ||
super().__init__(width=1, signed=False) | ||
self.integer = 1 | ||
|
||
def __str__(self): | ||
typestring = 'uint<1>' | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am truthfully not much of a fan of the typestring. What is it's function? Is it to have a string representation in the configs? There is not a 1:1 between a typestring and and the type. Part of me thinks this should be 'xnor' and not 'uint<1>', though this requires a few more changes downstream. (There would be a corresponding change for exponent precision types.) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not 100% sure, but this may be the last leftover from the previous way of doing things. I think that it is only used in |
||
return typestring | ||
|
||
|
||
class ExponentPrecisionType(IntegerPrecisionType): | ||
class ExponentPrecisionType(PrecisionType): | ||
""" | ||
Convenience class to differentiate 'regular' integers from those which represent exponents, | ||
for QKeras po2 quantizers, for example. | ||
|
@@ -329,6 +337,10 @@ class ExponentPrecisionType(IntegerPrecisionType): | |
def __init__(self, width=16, signed=True): | ||
super().__init__(width=width, signed=signed) | ||
|
||
def __str__(self): | ||
typestring = '{signed}int<{width}>'.format(signed='u' if not self.signed else '', width=self.width) | ||
return typestring | ||
|
||
|
||
def find_minimum_width(data, signed=True): | ||
""" | ||
|
@@ -536,34 +548,27 @@ def __next__(self): | |
if not self._iterator.finished: | ||
value = self._iterator[0] | ||
self._iterator.iternext() | ||
return self.precision_fmt % value | ||
return self.precision_fmt.format(value) | ||
else: | ||
raise StopIteration | ||
|
||
next = __next__ | ||
|
||
def update_precision(self, new_precision): | ||
self.type.precision = new_precision | ||
precision_str = str(self.type.precision) | ||
if 'int' in precision_str: | ||
self.precision_fmt = '%d' | ||
else: | ||
match = re.search('.+<(.+?)>', precision_str) | ||
if match is not None: | ||
precision_bits = match.group(1).split(',') | ||
width_bits = int(precision_bits[0]) | ||
integer_bits = int(precision_bits[1]) | ||
fractional_bits = integer_bits - width_bits | ||
lsb = 2**fractional_bits | ||
if lsb < 1: | ||
# Use str to represent the float with digits, get the length | ||
# to right of decimal point | ||
decimal_spaces = len(str(lsb).split('.')[1]) | ||
else: | ||
decimal_spaces = len(str(2**integer_bits)) | ||
self.precision_fmt = f'%.{decimal_spaces}f' | ||
if isinstance(new_precision, (IntegerPrecisionType, XnorPrecisionType, ExponentPrecisionType)): | ||
self.precision_fmt = '{:.0f}' | ||
elif isinstance(new_precision, FixedPrecisionType): | ||
if new_precision.fractional > 0: | ||
# Use str to represent the float with digits, get the length | ||
# to right of decimal point | ||
lsb = 2**-new_precision.fractional | ||
decimal_spaces = len(str(lsb).split('.')[1]) | ||
self.precision_fmt = f'{{:{decimal_spaces}f}}' | ||
else: | ||
self.precision_fmt = '%f' | ||
self.precision_fmt = '{:.0f}' | ||
else: | ||
raise RuntimeError(f"Unexpected new precision type: {new_precision}") | ||
|
||
|
||
class CompressedWeightVariable(WeightVariable): | ||
|
@@ -618,8 +623,8 @@ def __iter__(self): | |
|
||
def __next__(self): | ||
value = next(self._iterator) | ||
value_fmt = self.precision_fmt % value[2] | ||
return '{ %u, %u, %s }' % (value[1], value[0], value_fmt) | ||
value_fmt = self.precision_fmt.format(value[2]) | ||
return f'{{{value[1]}, {value[0]}, {value_fmt}}}' | ||
|
||
next = __next__ | ||
|
||
|
@@ -656,8 +661,8 @@ def __iter__(self): | |
|
||
def __next__(self): | ||
value = next(self._iterator) | ||
value_fmt = self.precision_fmt % value[1] | ||
return '{%d, %s}' % (value[0], value_fmt) | ||
value_fmt = self.precision_fmt.format(value[1]) | ||
return f'{{{value[0]}, {value_fmt}}}' | ||
|
||
next = __next__ | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Logically xnor is signed, even if we represent it as unit<1>. How it gets implemented should be a backend issue, not a definition issue. Leaving it unsigned for now, though, since that's a bigger change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the XNOR idea was that it is a single bit implementation, the more general definition of BNN is signed (-1 and 1), but that's a different case.