From d3fb0dd51650617b8964bb569cdbec646b401237 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 27 Jul 2022 08:27:57 -0400 Subject: [PATCH 01/48] added mixed-precision support --- src/goldeneye.py | 80 ++++++++++++++++++++++++++++++++++-------------- 1 file changed, 57 insertions(+), 23 deletions(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 047127a..5c7c676 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -6,6 +6,7 @@ # sys.path.append("./pytorchfi") from pytorchfi import core + # from num_sys_class import * @@ -40,8 +41,16 @@ def __init__( self.precision = precision # for simulated number system - (self.num_sys, self.num_sys_name) = num_sys - # self.num_sys = num_sys + + # TODO: Handle two options (1: uniform quantization so self.num_sys is one num_sys, 2: List of number systems) + self.num_sys = num_sys + + if type(num_sys) is not list: + (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys + elif len(num_sys) == 1: + # List with only one numsys means we have uniform quantization across the network + (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[0] + self.signed = kwargs.get("signed", True) # for quantization @@ -77,7 +86,7 @@ def _twos_comp(self, val, bits): def hook1_num_sys_inj1(self, in_num, bit_pos, to_inj): # Transform to num sys and bit flip if inj_order == 1 flip_val = to_inj and (self.inj_order == 1 or not self.quant) - out_num = self.num_sys.convert_numsys_flip(in_num, bit_pos, flip=flip_val) + out_num = self.cur_num_sys.convert_numsys_flip(in_num, bit_pos, flip=flip_val) return out_num def hook2_quant(self, in_num, max_value): @@ -142,7 +151,7 @@ def hook4_dequant(self, in_num, max_value): def hook5_num_sys_inj3(self, in_num, bit_pos, to_inj): # TODO only enter here if inj_order is 3. But check logic if this is the only time! Min: set flip = False - return self.num_sys.convert_numsys_flip( + return self.cur_num_sys.convert_numsys_flip( in_num, bit_pos, flip=(to_inj and (self.quant and self.inj_order == 6)) ) @@ -203,13 +212,27 @@ def quantizeUnsigned(self, X, B, R=2.0): S = 2.0 / R if getMode == "FP32": - return 0.5 * R * torch.min(torch.pow(torch.tensor(2.0).cuda(), 1.0 - B) * torch.round( - X * S * torch.pow(torch.tensor(2.0).cuda(), B - 1.0)), - 2.0 - torch.pow(torch.tensor(2.0).cuda(), 1.0 - B)) + return ( + 0.5 + * R + * torch.min( + torch.pow(torch.tensor(2.0).cuda(), 1.0 - B) + * torch.round(X * S * torch.pow(torch.tensor(2.0).cuda(), B - 1.0)), + 2.0 - torch.pow(torch.tensor(2.0).cuda(), 1.0 - B), + ) + ) elif getMode == "FP16": - return 0.5 * R * torch.min(torch.pow(torch.tensor(2.0).cuda().half(), 1.0 - B) * torch.round( - X * S * torch.pow(torch.tensor(2.0).cuda().half(), B - 1.0)), - 2.0 - torch.pow(torch.tensor(2.0).cuda().half(), 1.0 - B)) + return ( + 0.5 + * R + * torch.min( + torch.pow(torch.tensor(2.0).cuda().half(), 1.0 - B) + * torch.round( + X * S * torch.pow(torch.tensor(2.0).cuda().half(), B - 1.0) + ), + 2.0 - torch.pow(torch.tensor(2.0).cuda().half(), 1.0 - B), + ) + ) # operates on a single value def _flip_bit_goldeneye(self, orig_value, max_value, bit_pos=-1, to_inj=False): @@ -233,25 +256,29 @@ def _flip_bit_goldeneye(self, orig_value, max_value, bit_pos=-1, to_inj=False): return torch.tensor(max_value) # Quantization (num_sys to int8) - if self.num_sys_name == "INT": + if self.cur_num_sys_name == "INT": print("QUANTIZATION!") out_num = self.hook2_quant(out_num, max_value) - if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): return torch.tensor(out_num) + if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): + return torch.tensor(out_num) # Bit flip if inj_order == 2 if to_inj == 1: out_num = self.hook3_inj2(out_num, bit_pos) - if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): return torch.tensor(out_num) + if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): + return torch.tensor(out_num) # Dequant out_num = self.hook4_dequant(out_num, max_value) - if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): return torch.tensor(out_num) + if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): + return torch.tensor(out_num) # Num sys conversion + flip if inj_order = 3 - if to_inj == 6: # TODO Future datapath bitflip + if to_inj == 6: # TODO Future datapath bitflip print("HOOK 6!") out_num = self.hook5_num_sys_inj3(out_num, bit_pos, to_inj) - if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): return torch.tensor(out_num) + if torch.isnan(torch.tensor(out_num)) or torch.isinf(torch.tensor(out_num)): + return torch.tensor(out_num) # return torch.tensor(out_num, dtype=save_type) return torch.tensor(out_num) @@ -259,6 +286,13 @@ def _flip_bit_goldeneye(self, orig_value, max_value, bit_pos=-1, to_inj=False): def apply_goldeneye_transformation(self, module, input, output): corrupt_layer_set = self.get_corrupt_layer() range_max = self.get_layer_max(self.get_current_layer()) + + # Setting current num-sys for mixed-precision + if type(self.num_sys) is list: + (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[ + self.get_current_layer() + ] + logging.info("curr_conv", self.get_current_layer()) logging.info("range_max", range_max) @@ -282,10 +316,10 @@ def apply_goldeneye_transformation(self, module, input, output): self.corrupt_dim3[i], ) - if self.num_sys_name == "block_fp" and self.inj_order == 1: + if self.cur_num_sys_name == "block_fp" and self.inj_order == 1: # only select mantissa or sign bit - rand_bit = random.randint(0, self.num_sys.mant_len) - if rand_bit == self.num_sys.mant_len: + rand_bit = random.randint(0, self.cur_num_sys.mant_len) + if rand_bit == self.cur_num_sys.mant_len: rand_bit = self.bits - 1 else: rand_bit = self.bits - 1 - random.randint(0, self.bits - 1) @@ -313,8 +347,10 @@ def apply_goldeneye_transformation(self, module, input, output): # tensor conversions (FP32 -> Num Sys) # number system emulation (with meta injection support) if self.quant is False: - output[:] = self.num_sys.convert_numsys_tensor(output, meta_inj=meta_inj_en) - # output = self.num_sys.convert_numsys_tensor(output, meta_inj=meta_inj_en) + output[:] = self.cur_num_sys.convert_numsys_tensor( + output, meta_inj=meta_inj_en + ) + # output = self.cur_num_sys.convert_numsys_tensor(output, meta_inj=meta_inj_en) torch.cuda.empty_cache() else: # quantize (scale and quant NumSys) @@ -328,8 +364,6 @@ def apply_goldeneye_transformation(self, module, input, output): if self.get_current_layer() >= self.get_total_layers(): self.reset_current_layer() - - # baseDevice = output.get_device() # TO OPTIMIZE (??). Must move to CPU, then back to_device From c6be74c784e3c2a7727d8bb0738118d9b13de48c Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 00:05:06 -0400 Subject: [PATCH 02/48] added test_uniform unit-test --- {src => val}/test_goldeneye.py | 0 val/test_mixed_precision.py | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 68 insertions(+) rename {src => val}/test_goldeneye.py (100%) create mode 100644 val/test_mixed_precision.py diff --git a/src/test_goldeneye.py b/val/test_goldeneye.py similarity index 100% rename from src/test_goldeneye.py rename to val/test_goldeneye.py diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py new file mode 100644 index 0000000..21b07f3 --- /dev/null +++ b/val/test_mixed_precision.py @@ -0,0 +1,68 @@ +from src.goldeneye import goldeneye +from src.pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 +from src.util import * +from torch import nn +import timm + + +class TestMixedPrecision: + """ + Testing mixed-precision. + """ + + def setup_class(self): + # Prepare dataset and model + self.BATCH_SIZE = 4 + self.WORKERS = 1 + self.channels = 3 + self.img_size = 32 + self.USE_GPU = False + + self.model1, self.dataset = helper_setUp_CIFAR10(self.BATCH_SIZE, self.WORKERS) + + self.model2 = self.model1 + self.dataiter = iter(self.dataset) + + self.images, self.labels = self.dataiter.next() + + def test_uniform(num_sys_name): + + # Prepare goldeneye models for inference + + gmodel1 = goldeneye( + self.model1, + self.BATCH_SIZE, + use_cuda=self.USE_GPU, + quant=True, + layer_max=[], + inj_order=0, + num_sys=getNumSysName(num_sys_name), + ) + + inf_model1 = gmodel1.declare_neuron_fi( + function=gmodel1.apply_goldeneye_transformation + ) + + gmodel2 = goldeneye( + self.model2, + self.BATCH_SIZE, + use_cuda=self.USE_GPU, + quant=True, + layer_max=[], + inj_order=0, + num_sys=getNumSysName(num_sys_name), + ) + + inf_model2 = gmodel1.declare_neuron_fi( + function=gmodel1.apply_goldeneye_transformation + ) + + print("Testing uniform: ") + print(inf_model2(self.images)) + + print("Testing fake mixed: ") + print(inf_model1(self.images)) + + +if __name__ == "__main__": + print("Testing mixed-precision...") From c13f325d890250318226a240dc287f07e1fcc064 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 00:14:12 -0400 Subject: [PATCH 03/48] Added sif to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index e60dc8c..81f4f9d 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,4 @@ scripts/log/ src/data src/othermodels/*.py src/othermodels/state_dicts/*.pt +goldeneye.sif From 6d9634b1c6e9e798b19bc8abb93c1c7fddc2792b Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 00:51:41 -0400 Subject: [PATCH 04/48] changed import --- val/test_mixed_precision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 21b07f3..827d260 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,6 +1,6 @@ -from src.goldeneye import goldeneye -from src.pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 -from src.util import * +from goldeneye.src.goldeneye import goldeneye +from goldeneye.pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 +from goldeneye.src.util import * from torch import nn import timm From 1d66a6493a3f679e1e0d70e0a3b860aa05d62635 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 01:00:36 -0400 Subject: [PATCH 05/48] changed import 2 --- val/test_mixed_precision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 827d260..95de1f9 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,5 +1,5 @@ from goldeneye.src.goldeneye import goldeneye -from goldeneye.pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 +from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 from goldeneye.src.util import * from torch import nn import timm From cd9962b1cea304c12faa02fd9e1bc6f89d16be41 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 01:02:00 -0400 Subject: [PATCH 06/48] fixed import in goldeneye.py --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 5c7c676..b6bc208 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -5,7 +5,7 @@ import csv # sys.path.append("./pytorchfi") -from pytorchfi import core +from ..pytorchfi import core # from num_sys_class import * From 85798a6b9c9b7ef70189961eaf8c0acbac9e71ce Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 01:02:56 -0400 Subject: [PATCH 07/48] fixed import in goldeneye.py 2 --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index b6bc208..afc42ae 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -5,7 +5,7 @@ import csv # sys.path.append("./pytorchfi") -from ..pytorchfi import core +from ..pytorchfi.pytorchfi import core # from num_sys_class import * From 7c448c298729a0a2498bbd56c69af78d48a7097a Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 10:42:21 -0400 Subject: [PATCH 08/48] fixing imports in util --- src/util.py | 797 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 512 insertions(+), 285 deletions(-) diff --git a/src/util.py b/src/util.py index c4682a7..739f5be 100644 --- a/src/util.py +++ b/src/util.py @@ -9,17 +9,17 @@ import torchvision.models as models import timm import numpy as np -from num_sys_class import * +from .num_sys_class import * from othermodels import resnet, vgg, cifar10_nn -''' +""" Environment Variables -''' -DATASETS = os.environ['ML_DATASETS'] +""" +DATASETS = os.environ["ML_DATASETS"] -''' +""" Helper functions to parse input -''' +""" batchsize_in = -1 dnn_in = "" dataset_in = "" @@ -42,115 +42,145 @@ # QUANTIZE_BITS = 8 + def check_args(args=None): - parser = argparse.ArgumentParser(description='Arguments') - parser.add_argument('-b', '--batchsize', - help='Batch Size for inference', - type=int, - required='True', - default=8) - - parser.add_argument('-n', '--dnn', - help='Neural network', - required='True', - default='alexnet') - - parser.add_argument('-d', '--dataset', - help='CIFAR10, CIFAR100, or IMAGENET', - required='True', - default='IMAGENET') - - parser.add_argument('-f', '--format', - help='Data format: fp32, fp16, bfloat16, fixedpt', - required='True', - default='fp32') - - parser.add_argument('-P', '--precision', - help='FP32 or FP16', - default='FP16') - - parser.add_argument('-o', '--output', - help='output path', - default='../output/') - - parser.add_argument('-C', '--cuda', - help='True or False', - type=str2bool, - nargs='?', - const=True, - default=True) - - parser.add_argument('-i', '--injections', - help='The number of injections to perform', - type=int, - default=-1) - - parser.add_argument('-I', '--injectionLocation', - help='Injection Location (0-5)', - type=int, - default=-0) - - parser.add_argument('-R', '--radix', - help='Radix point for number format, from LSB', - type=int, - default=-1) - - parser.add_argument('-B', '--bitwidth', - help='Bitwidth of number format', - type=int, - default=32) - - parser.add_argument('-a', '--bias', - help='Bias value for AdaptivFloat number format', - type=int, - default=None) - - parser.add_argument('-r', '--training', - help='When enabled, this is training data. When disabled, this is testing data', - type=str2bool, - nargs='?', - const=True, - default=False) - - parser.add_argument('-w', '--workers', - help='Number of workers for dataloader', - type=int, - default=0) - - parser.add_argument('-q', '--quantize', - help='Enable neuron quantization (def=8 bits)', - type=str2bool, - nargs='?', - const=True, - default=False) - - parser.add_argument('-e', '--errormodel', - help='Single bit flip error model during quantization. -q needs to be enabled too', - type=str2bool, - nargs='?', - const=True, - default=False) - - parser.add_argument('-v', '--verbose', - help='True or False', - type=str2bool, - nargs='?', - const=True, - default=False) - - parser.add_argument('-D', '--debug', - help='True or False', - type=str2bool, - nargs='?', - const=True, - default=False) + parser = argparse.ArgumentParser(description="Arguments") + parser.add_argument( + "-b", + "--batchsize", + help="Batch Size for inference", + type=int, + required="True", + default=8, + ) + + parser.add_argument( + "-n", "--dnn", help="Neural network", required="True", default="alexnet" + ) + + parser.add_argument( + "-d", + "--dataset", + help="CIFAR10, CIFAR100, or IMAGENET", + required="True", + default="IMAGENET", + ) + + parser.add_argument( + "-f", + "--format", + help="Data format: fp32, fp16, bfloat16, fixedpt", + required="True", + default="fp32", + ) + + parser.add_argument("-P", "--precision", help="FP32 or FP16", default="FP16") + + parser.add_argument("-o", "--output", help="output path", default="../output/") + + parser.add_argument( + "-C", + "--cuda", + help="True or False", + type=str2bool, + nargs="?", + const=True, + default=True, + ) + + parser.add_argument( + "-i", + "--injections", + help="The number of injections to perform", + type=int, + default=-1, + ) + + parser.add_argument( + "-I", + "--injectionLocation", + help="Injection Location (0-5)", + type=int, + default=-0, + ) + + parser.add_argument( + "-R", + "--radix", + help="Radix point for number format, from LSB", + type=int, + default=-1, + ) + + parser.add_argument( + "-B", "--bitwidth", help="Bitwidth of number format", type=int, default=32 + ) + + parser.add_argument( + "-a", + "--bias", + help="Bias value for AdaptivFloat number format", + type=int, + default=None, + ) + + parser.add_argument( + "-r", + "--training", + help="When enabled, this is training data. When disabled, this is testing data", + type=str2bool, + nargs="?", + const=True, + default=False, + ) + + parser.add_argument( + "-w", "--workers", help="Number of workers for dataloader", type=int, default=0 + ) + + parser.add_argument( + "-q", + "--quantize", + help="Enable neuron quantization (def=8 bits)", + type=str2bool, + nargs="?", + const=True, + default=False, + ) + + parser.add_argument( + "-e", + "--errormodel", + help="Single bit flip error model during quantization. -q needs to be enabled too", + type=str2bool, + nargs="?", + const=True, + default=False, + ) + + parser.add_argument( + "-v", + "--verbose", + help="True or False", + type=str2bool, + nargs="?", + const=True, + default=False, + ) + + parser.add_argument( + "-D", + "--debug", + help="True or False", + type=str2bool, + nargs="?", + const=True, + default=False, + ) results = parser.parse_args(args) - global batchsize_in, dnn_in, dataset_in, format_in, precision_in, output_in, cuda_in, \ - bitwidth_in, radix_in, bias_in, \ - injections_in, injectionsLoc_in, training_in, workers_in, quantize_in, \ - verbose_in, debug_in + global batchsize_in, dnn_in, dataset_in, format_in, precision_in, output_in, cuda_in, bitwidth_in, radix_in, bias_in, injections_in, injectionsLoc_in, training_in, workers_in, quantize_in, verbose_in, debug_in # global singlebitflip_in batchsize_in = results.batchsize @@ -177,48 +207,114 @@ def check_args(args=None): # assert (quantize_in) -def getBatchsize(): return batchsize_in -def getDNN(): return dnn_in -def getDataset(): return dataset_in -def getFormat(): return format_in -def getPrecision(): return precision_in -def getOutputDir(): return output_in -def getCUDA_en(): return cuda_in +def getBatchsize(): + return batchsize_in + + +def getDNN(): + return dnn_in + + +def getDataset(): + return dataset_in + + +def getFormat(): + return format_in + + +def getPrecision(): + return precision_in + + +def getOutputDir(): + return output_in + + +def getCUDA_en(): + return cuda_in + + def getInjections(): if injections_in != -1 and injectionsLoc_in == 0: - print("Warning: No injection location. Please include \"-I\" flag with value.") + print('Warning: No injection location. Please include "-I" flag with value.') return injections_in -def getInjectionsLocation(): return injectionsLoc_in -def getRadix(): return radix_in -def getBitwidth(): return bitwidth_in -def getBias(): return bias_in -def getTraining_en(): return training_in -def getWorkers(): return workers_in -def getQuantize_en(): return quantize_in + + +def getInjectionsLocation(): + return injectionsLoc_in + + +def getRadix(): + return radix_in + + +def getBitwidth(): + return bitwidth_in + + +def getBias(): + return bias_in + + +def getTraining_en(): + return training_in + + +def getWorkers(): + return workers_in + + +def getQuantize_en(): + return quantize_in + + # def getQuantizeBits(): return QUANTIZE_BITS # def getSingleBitFlip_en(): return singlebitflip_in -def getVerbose(): return verbose_in -def getDebug(): return debug_in +def getVerbose(): + return verbose_in + + +def getDebug(): + return debug_in def printArgs(): - print('BATCH SIZE: \t%d\nDNN: \t\t%s\nDATASET: \t%sFORMAT: \t%s\n' \ - 'PRECISION: \t%s\nOUTPUT: \t%s\nUSE_CUDA: \t%s\n' \ - 'BIT-WIDTH: \t%s\nRADIX: \t%s\nBIAS: \t%s\n' \ - 'INJECTIONS: \t%s\nINJECTIONS LOCATION: \t%s\nTRAINING DATA: \t%s\nWORKERS: \t%d\n' \ - 'VERBOSE: \t%s\nDEBUG: \t\t%s\n' \ - % (batchsize_in, dnn_in, dataset_in, format_in, precision_in, output_in, cuda_in, \ - bitwidth_in, radix_in, bias_in, \ - injections_in, injectionsLoc_in, training_in, workers_in, verbose_in, debug_in)) + print( + "BATCH SIZE: \t%d\nDNN: \t\t%s\nDATASET: \t%sFORMAT: \t%s\n" + "PRECISION: \t%s\nOUTPUT: \t%s\nUSE_CUDA: \t%s\n" + "BIT-WIDTH: \t%s\nRADIX: \t%s\nBIAS: \t%s\n" + "INJECTIONS: \t%s\nINJECTIONS LOCATION: \t%s\nTRAINING DATA: \t%s\nWORKERS: \t%d\n" + "VERBOSE: \t%s\nDEBUG: \t\t%s\n" + % ( + batchsize_in, + dnn_in, + dataset_in, + format_in, + precision_in, + output_in, + cuda_in, + bitwidth_in, + radix_in, + bias_in, + injections_in, + injectionsLoc_in, + training_in, + workers_in, + verbose_in, + debug_in, + ) + ) def str2bool(v): - if v.lower() in ('yes', 'true', 't', 'y', '1'): + if v.lower() in ("yes", "true", "t", "y", "1"): return True - elif v.lower() in ('no', 'false', 'f', 'n', '0'): + elif v.lower() in ("no", "false", "f", "n", "0"): return False else: - raise argparse.ArgumentTypeError('Boolean value expected.') + raise argparse.ArgumentTypeError("Boolean value expected.") + # def getNumSysName(name): # if name == "fp32": @@ -232,61 +328,91 @@ def str2bool(v): # returns the number of classes for common datasets def getNumClasses(dataset): - if(dataset == 'CIFAR10'): + if dataset == "CIFAR10": return 10 - elif(dataset == 'CIFAR100'): + elif dataset == "CIFAR100": return 100 - elif(dataset == 'IMAGENET'): + elif dataset == "IMAGENET": return 1000 def getNetwork(networkName, DATASET): ####### IMAGENET ####### - FB_repo = 'facebookresearch/deit:main' - if DATASET == 'IMAGENET': + FB_repo = "facebookresearch/deit:main" + if DATASET == "IMAGENET": # Convolution Neural Networks - if networkName == "alexnet": MODEL = models.alexnet(pretrained=True, progress=True) - elif networkName == "vgg11": MODEL = models.vgg11(pretrained=True, progress=True) - elif networkName == "vgg13": MODEL = models.vgg13(pretrained=True, progress=True) - elif networkName == "vgg16": MODEL = models.vgg16(pretrained=True, progress=True) - elif networkName == "vgg19": MODEL = models.vgg19(pretrained=True, progress=True) - elif networkName == "vgg11_bn": MODEL = models.vgg11(pretrained=True, progress=True) - elif networkName == "vgg13_bn": MODEL = models.vgg13(pretrained=True, progress=True) - elif networkName == "vgg16_bn": MODEL = models.vgg16(pretrained=True, progress=True) - elif networkName == "vgg19_bn": MODEL = models.vgg19(pretrained=True, progress=True) - elif networkName == "resnet18": MODEL = models.resnet18(pretrained=True, progress=True) - elif networkName == "resnet34": MODEL = models.resnet34(pretrained=True, progress=True) - elif networkName == "resnet50": MODEL = models.resnet50(pretrained=True, progress=True) - elif networkName == "resnet101": MODEL = models.resnet101(pretrained=True, progress=True) - elif networkName == "resnet152": MODEL = models.resnet152(pretrained=True, progress=True) - elif networkName == "squeezenet1_0": MODEL = models.squeezenet1_0(pretrained=True, progress=True) - elif networkName == "squeezenet1_1": MODEL = models.squeezenet1_1(pretrained=True, progress=True) - elif networkName == "densenet121": MODEL = models.densenet121(pretrained=True, progress=True) - elif networkName == "densenet169": MODEL = models.densenet169(pretrained=True, progress=True) - elif networkName == "densenet201": MODEL = models.densenet201(pretrained=True, progress=True) - elif networkName == "densenet161": MODEL = models.densenet161(pretrained=True, progress=True) - elif networkName == "inceptionv3": MODEL = models.inception_v3(pretrained=True, progress=True) - elif networkName == "googlenet": MODEL = models.googlenet(pretrained=True, progress=True) - elif networkName == "shufflenet": MODEL = models.shufflenet_v2_x1_0(pretrained=True, progress=True) - elif networkName == "mobilenet": MODEL = models.mobilenet_v2(pretrained=True, progress=True) - elif networkName == "resnext50_32x4d": MODEL = models.resnext50_32x4d(pretrained=True, progress=True) + if networkName == "alexnet": + MODEL = models.alexnet(pretrained=True, progress=True) + elif networkName == "vgg11": + MODEL = models.vgg11(pretrained=True, progress=True) + elif networkName == "vgg13": + MODEL = models.vgg13(pretrained=True, progress=True) + elif networkName == "vgg16": + MODEL = models.vgg16(pretrained=True, progress=True) + elif networkName == "vgg19": + MODEL = models.vgg19(pretrained=True, progress=True) + elif networkName == "vgg11_bn": + MODEL = models.vgg11(pretrained=True, progress=True) + elif networkName == "vgg13_bn": + MODEL = models.vgg13(pretrained=True, progress=True) + elif networkName == "vgg16_bn": + MODEL = models.vgg16(pretrained=True, progress=True) + elif networkName == "vgg19_bn": + MODEL = models.vgg19(pretrained=True, progress=True) + elif networkName == "resnet18": + MODEL = models.resnet18(pretrained=True, progress=True) + elif networkName == "resnet34": + MODEL = models.resnet34(pretrained=True, progress=True) + elif networkName == "resnet50": + MODEL = models.resnet50(pretrained=True, progress=True) + elif networkName == "resnet101": + MODEL = models.resnet101(pretrained=True, progress=True) + elif networkName == "resnet152": + MODEL = models.resnet152(pretrained=True, progress=True) + elif networkName == "squeezenet1_0": + MODEL = models.squeezenet1_0(pretrained=True, progress=True) + elif networkName == "squeezenet1_1": + MODEL = models.squeezenet1_1(pretrained=True, progress=True) + elif networkName == "densenet121": + MODEL = models.densenet121(pretrained=True, progress=True) + elif networkName == "densenet169": + MODEL = models.densenet169(pretrained=True, progress=True) + elif networkName == "densenet201": + MODEL = models.densenet201(pretrained=True, progress=True) + elif networkName == "densenet161": + MODEL = models.densenet161(pretrained=True, progress=True) + elif networkName == "inceptionv3": + MODEL = models.inception_v3(pretrained=True, progress=True) + elif networkName == "googlenet": + MODEL = models.googlenet(pretrained=True, progress=True) + elif networkName == "shufflenet": + MODEL = models.shufflenet_v2_x1_0(pretrained=True, progress=True) + elif networkName == "mobilenet": + MODEL = models.mobilenet_v2(pretrained=True, progress=True) + elif networkName == "resnext50_32x4d": + MODEL = models.resnext50_32x4d(pretrained=True, progress=True) # transformers - elif networkName == "vit_base": MODEL = timm.create_model("vit_base_patch16_224", pretrained=True) - elif networkName == "deit_base": MODEL = torch.hub.load(FB_repo, 'deit_base_patch16_224', pretrained=True) - elif networkName == "deit_tiny": MODEL = torch.hub.load(FB_repo, 'deit_tiny_patch16_224', pretrained=True) + elif networkName == "vit_base": + MODEL = timm.create_model("vit_base_patch16_224", pretrained=True) + elif networkName == "deit_base": + MODEL = torch.hub.load(FB_repo, "deit_base_patch16_224", pretrained=True) + elif networkName == "deit_tiny": + MODEL = torch.hub.load(FB_repo, "deit_tiny_patch16_224", pretrained=True) # Error else: sys.exit("Network does not exist") - elif DATASET == 'CIFAR10' or DATASET == 'CIFAR100': + elif DATASET == "CIFAR10" or DATASET == "CIFAR100": if networkName == "resnet18": MODEL = resnet.resnet18(pretrained=True) elif networkName == "vgg19_bn": MODEL = vgg.vgg19_bn(pretrained=True) elif networkName == "cifar10_nn_baseline": - MODEL = cifar10_nn.baseline(pretrained=True, output_size=getNumClasses(DATASET)) + MODEL = cifar10_nn.baseline( + pretrained=True, output_size=getNumClasses(DATASET) + ) elif networkName == "cifar10_nn_v1": MODEL = cifar10_nn.v1(pretrained=True, output_size=getNumClasses(DATASET)) elif networkName == "cifar10_nn_v2": @@ -299,134 +425,209 @@ def getNetwork(networkName, DATASET): # model upgrades if getCUDA_en(): MODEL = MODEL.cuda() - if getPrecision() == 'FP16': + if getPrecision() == "FP16": MODEL = MODEL.half() return MODEL -def load_dataset(DATASET, BATCH_SIZE, workers=0, training=False, shuffleIn=False, include_id=True): - if DATASET == 'CIFAR10': + +def load_dataset( + DATASET, BATCH_SIZE, workers=0, training=False, shuffleIn=False, include_id=True +): + if DATASET == "CIFAR10": transform = transforms.Compose( - [ - transforms.ToTensor(), - transforms.Normalize((0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)) - ] - ) + [ + transforms.ToTensor(), + transforms.Normalize( + (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) + ), + ] + ) if include_id: - testset = IdCifar10(root='./data', train=training, download=True, transform=transform) + testset = IdCifar10( + root="./data", train=training, download=True, transform=transform + ) else: - testset = datasets.CIFAR10(root='./data', train=training, download=True, transform=transform) + testset = datasets.CIFAR10( + root="./data", train=training, download=True, transform=transform + ) - test_loader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE, - shuffle=shuffleIn, num_workers=workers, pin_memory=True) + test_loader = torch.utils.data.DataLoader( + testset, + batch_size=BATCH_SIZE, + shuffle=shuffleIn, + num_workers=workers, + pin_memory=True, + ) dataiter = iter(test_loader) - elif DATASET == 'CIFAR100': + elif DATASET == "CIFAR100": transform = transforms.Compose( - [ - transforms.ToTensor(), - transforms.Normalize((0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)) - ] - ) + [ + transforms.ToTensor(), + transforms.Normalize( + (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) + ), + ] + ) if include_id: - testset = IdCifar100(root='./data', train=training, download=True, transform=transform) + testset = IdCifar100( + root="./data", train=training, download=True, transform=transform + ) else: - testset = datasets.CIFAR100(root='./data', train=training, download=True, transform=transform) + testset = datasets.CIFAR100( + root="./data", train=training, download=True, transform=transform + ) - test_loader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE, - shuffle=shuffleIn, num_workers=workers, pin_memory=True) + test_loader = torch.utils.data.DataLoader( + testset, + batch_size=BATCH_SIZE, + shuffle=shuffleIn, + num_workers=workers, + pin_memory=True, + ) dataiter = iter(test_loader) - elif DATASET == 'IMAGENET': + elif DATASET == "IMAGENET": if training == False: - valdir = os.path.join(DATASETS + '/imagenet/', 'val') + valdir = os.path.join(DATASETS + "/imagenet/", "val") + else: + valdir = os.path.join(DATASETS + "/imagenet/", "train") + normalize = transforms.Normalize( + mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] + ) + transform = transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ] + ) + + if include_id: + images = IdImageFolder(valdir, transform=transform) else: - valdir = os.path.join(DATASETS + '/imagenet/', 'train') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - transform = transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ]) - - if include_id: images = IdImageFolder(valdir, transform=transform) - else: images = datasets.ImageFolder(valdir, transform=transform) - - val_loader = torch.utils.data.DataLoader(images, batch_size=BATCH_SIZE, - shuffle=shuffleIn, num_workers=workers, pin_memory=True) + images = datasets.ImageFolder(valdir, transform=transform) + + val_loader = torch.utils.data.DataLoader( + images, + batch_size=BATCH_SIZE, + shuffle=shuffleIn, + num_workers=workers, + pin_memory=True, + ) dataiter = iter(val_loader) return dataiter # total_data refers to the total size of the data_loader, for all images desired -def load_custom_dataset(NETWORK, DATASET, BATCH_SIZE, good_images, total_data, - workers = 0, random=True, replacement=True, single=False, singleIndex=0): +def load_custom_dataset( + NETWORK, + DATASET, + BATCH_SIZE, + good_images, + total_data, + workers=0, + random=True, + replacement=True, + single=False, + singleIndex=0, +): if random: if replacement: if single == False: custom_sampler = get_custom_sampler(good_images, total_data) else: - custom_sampler = get_custom_sampler_single(good_images, singleIndex, total_data) + custom_sampler = get_custom_sampler_single( + good_images, singleIndex, total_data + ) else: custom_sampler = get_custom_sampler_no_replacement(good_images, total_data) else: custom_sampler = get_custom_sampler_full(good_images) - if DATASET == 'CIFAR10': - transform = transforms.Compose( - [ - transforms.ToTensor(), - transforms.Normalize((0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)) - ] - ) + if DATASET == "CIFAR10": + transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize( + (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) + ), + ] + ) + + testset = IdCifar10( + root="./data", train=False, download=True, transform=transform + ) + test_loader = torch.utils.data.DataLoader( + testset, + batch_size=BATCH_SIZE, + sampler=custom_sampler, + num_workers=workers, + pin_memory=True, + ) + dataiter = iter(test_loader) - testset = IdCifar10(root='./data', train=False, - download=True, transform=transform) - test_loader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE, - sampler=custom_sampler, num_workers=workers, pin_memory=True) - dataiter = iter(test_loader) - - if DATASET == 'CIFAR100': - transform = transforms.Compose( - [ - transforms.ToTensor(), - transforms.Normalize((0.4914,0.4822,0.4465), (0.2023,0.1994,0.2010)) - ] - ) + if DATASET == "CIFAR100": + transform = transforms.Compose( + [ + transforms.ToTensor(), + transforms.Normalize( + (0.4914, 0.4822, 0.4465), (0.2023, 0.1994, 0.2010) + ), + ] + ) + + testset = IdCifar100( + root="./data", train=False, download=True, transform=transform + ) + test_loader = torch.utils.data.DataLoader( + testset, + batch_size=BATCH_SIZE, + sampler=custom_sampler, + num_workers=workers, + pin_memory=True, + ) + dataiter = iter(test_loader) + + if DATASET == "IMAGENET": - testset = IdCifar100(root='./data', train=False, - download=True, transform=transform) - test_loader = torch.utils.data.DataLoader(testset, batch_size=BATCH_SIZE, - sampler=custom_sampler, num_workers=workers, pin_memory=True) - dataiter = iter(test_loader) - - if DATASET == 'IMAGENET': - - valdir = os.path.join(DATASETS + '/imagenet/', 'val') - normalize = transforms.Normalize(mean=[0.485, 0.456, 0.406], - std=[0.229, 0.224, 0.225]) - images = IdImageFolder(valdir, transforms.Compose([ - transforms.Resize(256), - transforms.CenterCrop(224), - transforms.ToTensor(), - normalize, - ])) - val_loader = torch.utils.data.DataLoader(images, batch_size=BATCH_SIZE, - num_workers = workers, sampler=custom_sampler, pin_memory=True) - dataiter = iter(val_loader) + valdir = os.path.join(DATASETS + "/imagenet/", "val") + normalize = transforms.Normalize( + mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225] + ) + images = IdImageFolder( + valdir, + transforms.Compose( + [ + transforms.Resize(256), + transforms.CenterCrop(224), + transforms.ToTensor(), + normalize, + ] + ), + ) + val_loader = torch.utils.data.DataLoader( + images, + batch_size=BATCH_SIZE, + num_workers=workers, + sampler=custom_sampler, + pin_memory=True, + ) + dataiter = iter(val_loader) return dataiter + class IdCifar10(datasets.CIFAR10): - def __init__(self, root, train=False, - transform=None, target_transform=None, - download=False): + def __init__( + self, root, train=False, transform=None, target_transform=None, download=False + ): super(datasets.CIFAR10, self).__init__(root) self.transform = transform @@ -435,8 +636,10 @@ def __init__(self, root, train=False, if download: self.download() if not self._check_integrity(): - raise RuntimeError('Dataset not found or corrupted.' + - ' You can use download=True to download it') + raise RuntimeError( + "Dataset not found or corrupted." + + " You can use download=True to download it" + ) if self.train: downloaded_list = self.train_list else: @@ -447,17 +650,17 @@ def __init__(self, root, train=False, # now load the picked numpy arrays for file_name, checksum in downloaded_list: file_path = os.path.join(self.root, self.base_folder, file_name) - with open(file_path, 'rb') as f: + with open(file_path, "rb") as f: if sys.version_info[0] == 2: entry = cPickle.load(f) else: - entry = cPickle.load(f, encoding='latin1') - self.data.append(entry['data']) - if 'labels' in entry: - self.targets.extend(entry['labels']) + entry = cPickle.load(f, encoding="latin1") + self.data.append(entry["data"]) + if "labels" in entry: + self.targets.extend(entry["labels"]) else: - self.targets.extend(entry['fine_labels']) - self.img_names.extend(entry['filenames']) + self.targets.extend(entry["fine_labels"]) + self.img_names.extend(entry["filenames"]) self.data = np.vstack(self.data).reshape(-1, 3, 32, 32) self.data = self.data.transpose((0, 2, 3, 1)) # convert to HWC @@ -465,28 +668,29 @@ def __init__(self, root, train=False, def __getitem__(self, index): img, target, path = self.data[index], self.targets[index], self.img_names[index] - #img = Image.fromarray(img) + # img = Image.fromarray(img) if self.transform is not None: img = self.transform(img) if self.target_transform is not None: target = self.target_transform(target) return img, target, path, index + class IdCifar100(IdCifar10): - base_folder = 'cifar-100-python' + base_folder = "cifar-100-python" url = "https://www.cs.toronto.edu/~kriz/cifar-100-python.tar.gz" filename = "cifar-100-python.tar.gz" - tgz_md5 = 'eb9058c3a382ffc7106e4002c42a8d85' + tgz_md5 = "eb9058c3a382ffc7106e4002c42a8d85" train_list = [ - ['train', '16019d7e3df5f24257cddd939b257f8d'], + ["train", "16019d7e3df5f24257cddd939b257f8d"], ] test_list = [ - ['test', 'f0ef6b0ae62326f3e7ffdfab6717acfc'], + ["test", "f0ef6b0ae62326f3e7ffdfab6717acfc"], ] meta = { - 'filename': 'meta', - 'key': 'fine_label_names', - 'md5': '7973b15100ade9c7d40fb424638fde48', + "filename": "meta", + "key": "fine_label_names", + "md5": "7973b15100ade9c7d40fb424638fde48", } @@ -496,29 +700,38 @@ def __getitem__(self, index): path = self.imgs[index][0] return item[0], item[1], path, index + class Custom_Sampler(torch.utils.data.Sampler): def __init__(self, data): self.data = data + def __iter__(self): return iter(self.data) + def __len__(self): return len(self.data) + """ Edit this to make the random selector Input: list of good indices Return: list of indices that will be used to load data """ + + def random_selector(indices, total): return random.choices(indices, k=total) + def single_selector(indices, index, total): single_index = [indices[index]] return random.choices(single_index, k=total) + def random_selector_no_replacement(indices, total): return random.sample(indices, k=total) + def get_custom_sampler(indices, total): # Use random sampling with replacement indices = random_selector(indices, total) @@ -528,6 +741,7 @@ def get_custom_sampler(indices, total): return sampler + def get_custom_sampler_single(indices, index, total): # Use random sampling with replacement indices = single_selector(indices, index, total) @@ -537,6 +751,7 @@ def get_custom_sampler_single(indices, index, total): return sampler + def get_custom_sampler_no_replacement(indices, total): # Use random sampling with replacement indices = random_selector_no_replacement(indices, total) @@ -546,6 +761,7 @@ def get_custom_sampler_no_replacement(indices, total): return sampler + def get_custom_sampler_full(indices): # Create custom sampler sampler = Custom_Sampler(indices) @@ -563,6 +779,7 @@ def getMaxClass(tensor, dim=0): diff_top2 = (top2[0] - top2[1]) * 100 return argmax, conf, diff_top2.item() + def getMaxClass_parallel(tensor_in, dim=0): tensor = F.softmax(tensor_in) argmax = torch.argmax(tensor).item() @@ -571,12 +788,14 @@ def getMaxClass_parallel(tensor_in, dim=0): diff_top2 = (top2[0] - top2[1]) * 100 return argmax, conf, diff_top2.item() + # from https://stackoverflow.com/questions/34968722/how-to-implement-the-softmax-function-in-python def softmax(x): """Compute softmax values for each sets of scores in x.""" e_x = np.exp(x - np.max(x)) return e_x / e_x.sum(axis=0) + def diff_top2(data): return (data[0] - data[1]).item() * 100 @@ -584,22 +803,26 @@ def diff_top2(data): ################################################################# ##################### HELPER METHODS FOR I/O #################### ################################################################# -def save_data(path, file_name, data, compress = True): +def save_data(path, file_name, data, compress=True): if not os.path.exists(path): os.makedirs(path) output = path + file_name + ".p" - f = bz2.BZ2File(output + ".bz2","wb") if compress else open(fname,"wb") + f = bz2.BZ2File(output + ".bz2", "wb") if compress else open(fname, "wb") cPickle.dump(data, f) f.close() - -def load_file(file_name, compress = True): - f = bz2.BZ2File(file_name + '.p.bz2', "rb") if compress else open(file_name.strip('.p.bz2'),"rb") - fileIn= cPickle.load(f) +def load_file(file_name, compress=True): + f = ( + bz2.BZ2File(file_name + ".p.bz2", "rb") + if compress + else open(file_name.strip(".p.bz2"), "rb") + ) + fileIn = cPickle.load(f) f.close() return fileIn + ################################################################# ################### HELPER METHODS FOR NUMSYS ################### ################################################################# @@ -608,7 +831,7 @@ def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): if name == "fp32": return num_fp32(), name if name == "INT": - assert(getQuantize_en()) + assert getQuantize_en() return num_fp32(), name elif name == "fp16": return num_fp16(), name @@ -623,8 +846,12 @@ def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): elif name == "block_fp": return block_fp(bit_width=bits, exp_len=radix_up, mant_len=radix_down), name elif name == "adaptive_fp": - return adaptive_float(bit_width=bits, exp_len=radix_up, mant_len=radix_down, exp_bias=bias), name + return ( + adaptive_float( + bit_width=bits, exp_len=radix_up, mant_len=radix_down, exp_bias=bias + ), + name, + ) else: sys.exit("Number format not supported") - From e78dba42f046dfd9964e461eb3b33d1697f03e98 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 11:00:13 -0400 Subject: [PATCH 09/48] fixing imports in util 2 --- val/test_mixed_precision.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 95de1f9..e197365 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,6 +1,7 @@ from goldeneye.src.goldeneye import goldeneye from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 -from goldeneye.src.util import * + +# from goldeneye.src.util import * from torch import nn import timm From 257681a86f075bfa1daa1016b954e75c44c71f9e Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 11:02:36 -0400 Subject: [PATCH 10/48] fixed self in test_mixed_precision --- val/test_mixed_precision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index e197365..9fbc401 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -26,7 +26,7 @@ def setup_class(self): self.images, self.labels = self.dataiter.next() - def test_uniform(num_sys_name): + def test_uniform(self, num_sys_name): # Prepare goldeneye models for inference From 01a76ffbaca1afaf4f849775d2da0f0c0a76f714 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 12:10:36 -0400 Subject: [PATCH 11/48] added pytest fixture --- val/test_mixed_precision.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 9fbc401..d66d396 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -4,6 +4,7 @@ # from goldeneye.src.util import * from torch import nn import timm +import pytest class TestMixedPrecision: @@ -11,6 +12,18 @@ class TestMixedPrecision: Testing mixed-precision. """ + def pytest_addoption(parser): + parser.addoption( + "--num-sys-name", + action="store", + default="fp32", + help="provide a num sys arg to run the test with", + ) + + @pytest.fixture + def cmdopt(request): + return request.config.getoption("--num-sys-name") + def setup_class(self): # Prepare dataset and model self.BATCH_SIZE = 4 From 8375982f417dd503c34898a893c4a831e66465fe Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:28:55 -0400 Subject: [PATCH 12/48] adding fixture --- val/conftest.py | 13 +++++++++++++ val/test_mixed_precision.py | 13 ------------- 2 files changed, 13 insertions(+), 13 deletions(-) create mode 100644 val/conftest.py diff --git a/val/conftest.py b/val/conftest.py new file mode 100644 index 0000000..d6a4b05 --- /dev/null +++ b/val/conftest.py @@ -0,0 +1,13 @@ +import pytest + +def pytest_addoption(parser): + parser.addoption( + "--num-sys-name", + action="store", + default="fp32", + help="provide a num sys arg to run the test with", + ) + + @pytest.fixture + def cmdopt(request): + return request.config.getoption("--num-sys-name") \ No newline at end of file diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index d66d396..9fbc401 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -4,7 +4,6 @@ # from goldeneye.src.util import * from torch import nn import timm -import pytest class TestMixedPrecision: @@ -12,18 +11,6 @@ class TestMixedPrecision: Testing mixed-precision. """ - def pytest_addoption(parser): - parser.addoption( - "--num-sys-name", - action="store", - default="fp32", - help="provide a num sys arg to run the test with", - ) - - @pytest.fixture - def cmdopt(request): - return request.config.getoption("--num-sys-name") - def setup_class(self): # Prepare dataset and model self.BATCH_SIZE = 4 From d271f4b10cdf4c6d2795e7724ec7a7ad014c7789 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:32:56 -0400 Subject: [PATCH 13/48] adding fixture 1 --- val/conftest.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/val/conftest.py b/val/conftest.py index d6a4b05..23c45ca 100644 --- a/val/conftest.py +++ b/val/conftest.py @@ -1,13 +1,15 @@ import pytest + def pytest_addoption(parser): - parser.addoption( - "--num-sys-name", - action="store", - default="fp32", - help="provide a num sys arg to run the test with", - ) - - @pytest.fixture - def cmdopt(request): - return request.config.getoption("--num-sys-name") \ No newline at end of file + parser.addoption( + "--num-sys-name", + action="store", + default="fp32", + help="provide a num sys arg to run the test with", + ) + + +@pytest.fixture +def params(request): + return request.config.getoption("--num-sys-name") From a0f554b560c203a3f2e120d0e4dcbba67bfe0df4 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:38:03 -0400 Subject: [PATCH 14/48] adding fixture 2 --- val/conftest.py | 13 ++++++++++++- val/test_mixed_precision.py | 3 ++- 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/val/conftest.py b/val/conftest.py index 23c45ca..ba6eb60 100644 --- a/val/conftest.py +++ b/val/conftest.py @@ -8,8 +8,19 @@ def pytest_addoption(parser): default="fp32", help="provide a num sys arg to run the test with", ) + parser.addoption( + "--model", + action="store", + default="alexnet", + help="provide a num sys arg to run the test with", + ) @pytest.fixture def params(request): - return request.config.getoption("--num-sys-name") + params = {} + params["num_sys_name"] = request.config.getoption("--num-sys-name") + params["model"] = request.config.getoption("--model") + # if params["num_sys_name"] is None or params["password"] is None: + # pytest.skip() + return params diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 9fbc401..695dc5a 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -26,9 +26,10 @@ def setup_class(self): self.images, self.labels = self.dataiter.next() - def test_uniform(self, num_sys_name): + def test_uniform(self, params): # Prepare goldeneye models for inference + self.num_sys_name = params["num_sys_name"] gmodel1 = goldeneye( self.model1, From 9d8c7cadf7d954af665a5dd8506dd1080d0df136 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:51:18 -0400 Subject: [PATCH 15/48] adding fixture 3 --- val/test_mixed_precision.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 695dc5a..129f2b5 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,5 +1,6 @@ from goldeneye.src.goldeneye import goldeneye from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 +from ..src.num_sys_class import * # from goldeneye.src.util import * from torch import nn @@ -66,5 +67,39 @@ def test_uniform(self, params): print(inf_model1(self.images)) +################################################################# +################### HELPER METHODS FOR NUMSYS ################### +################################################################# +def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): + # common number systems in PyTorch + if name == "fp32": + return num_fp32(), name + if name == "INT": + assert getQuantize_en() + return num_fp32(), name + elif name == "fp16": + return num_fp16(), name + elif name == "bfloat16": + return num_bfloat16(), name + + # generic number systems in PyTorch + elif name == "fp_n": + return num_float_n(exp_len=radix_up, mant_len=radix_down), name + elif name == "fxp_n": + return num_fixed_pt(int_len=radix_up, frac_len=radix_down), name + elif name == "block_fp": + return block_fp(bit_width=bits, exp_len=radix_up, mant_len=radix_down), name + elif name == "adaptive_fp": + return ( + adaptive_float( + bit_width=bits, exp_len=radix_up, mant_len=radix_down, exp_bias=bias + ), + name, + ) + + else: + sys.exit("Number format not supported") + + if __name__ == "__main__": print("Testing mixed-precision...") From 14ca1387c7f92e1c3ec5d4617583e8c998619a3e Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:54:13 -0400 Subject: [PATCH 16/48] test_mixed_precision debug --- val/test_mixed_precision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 129f2b5..6b14d51 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -39,7 +39,7 @@ def test_uniform(self, params): quant=True, layer_max=[], inj_order=0, - num_sys=getNumSysName(num_sys_name), + num_sys=getNumSysName(self.num_sys_name), ) inf_model1 = gmodel1.declare_neuron_fi( @@ -53,7 +53,7 @@ def test_uniform(self, params): quant=True, layer_max=[], inj_order=0, - num_sys=getNumSysName(num_sys_name), + num_sys=getNumSysName(self.num_sys_name), ) inf_model2 = gmodel1.declare_neuron_fi( From b40b898ddffbfae4a4f5d99375992a7824c39b21 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 29 Jul 2022 13:55:20 -0400 Subject: [PATCH 17/48] test_mixed_precision debug 1 --- val/test_mixed_precision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 6b14d51..3a47b23 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -75,7 +75,7 @@ def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): if name == "fp32": return num_fp32(), name if name == "INT": - assert getQuantize_en() + # assert getQuantize_en() return num_fp32(), name elif name == "fp16": return num_fp16(), name From 4380a1379703a818386e0f9c128f1df5fbe0c243 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Tue, 2 Aug 2022 11:12:35 -0400 Subject: [PATCH 18/48] test_mixed_precision debug 2 --- val/test_mixed_precision.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 3a47b23..a757c60 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,6 +1,7 @@ from goldeneye.src.goldeneye import goldeneye from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 from ..src.num_sys_class import * +import copy # from goldeneye.src.util import * from torch import nn @@ -22,7 +23,7 @@ def setup_class(self): self.model1, self.dataset = helper_setUp_CIFAR10(self.BATCH_SIZE, self.WORKERS) - self.model2 = self.model1 + self.model2 = copy.deepcopy(self.model1) self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() @@ -61,10 +62,10 @@ def test_uniform(self, params): ) print("Testing uniform: ") - print(inf_model2(self.images)) + print(inf_model2(self.images[0])) print("Testing fake mixed: ") - print(inf_model1(self.images)) + print(inf_model1(self.images[0])) ################################################################# From 4e3195b9388dfb62b0c50a840ccf1c3ebb60e2cd Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:13:47 -0400 Subject: [PATCH 19/48] test_mixed_precision debug 3 --- val/test_mixed_precision.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index a757c60..6c2ffcb 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -22,6 +22,7 @@ def setup_class(self): self.USE_GPU = False self.model1, self.dataset = helper_setUp_CIFAR10(self.BATCH_SIZE, self.WORKERS) + self.model1.eval() self.model2 = copy.deepcopy(self.model1) self.dataiter = iter(self.dataset) @@ -62,10 +63,10 @@ def test_uniform(self, params): ) print("Testing uniform: ") - print(inf_model2(self.images[0])) + print(inf_model2(self.images)) print("Testing fake mixed: ") - print(inf_model1(self.images[0])) + print(inf_model1(self.images)) ################################################################# From ee4841fe068590cedd58c41c65804e99a6d7da6a Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:21:53 -0400 Subject: [PATCH 20/48] test_mixed_precision debug 4 --- val/test_mixed_precision.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 6c2ffcb..1926892 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -39,7 +39,6 @@ def test_uniform(self, params): self.BATCH_SIZE, use_cuda=self.USE_GPU, quant=True, - layer_max=[], inj_order=0, num_sys=getNumSysName(self.num_sys_name), ) @@ -53,7 +52,6 @@ def test_uniform(self, params): self.BATCH_SIZE, use_cuda=self.USE_GPU, quant=True, - layer_max=[], inj_order=0, num_sys=getNumSysName(self.num_sys_name), ) From 04e9d5c136bbec5dc7c3239f9efb29827a3d37e5 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:27:49 -0400 Subject: [PATCH 21/48] test_mixed_precision debug 5 --- val/test_mixed_precision.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 1926892..7291ee4 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -37,6 +37,7 @@ def test_uniform(self, params): gmodel1 = goldeneye( self.model1, self.BATCH_SIZE, + input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, quant=True, inj_order=0, @@ -50,6 +51,7 @@ def test_uniform(self, params): gmodel2 = goldeneye( self.model2, self.BATCH_SIZE, + input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, quant=True, inj_order=0, From a02f0d9b80a87724abcec1c4f78acff0bca05e24 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:48:57 -0400 Subject: [PATCH 22/48] Added mixed-precision back --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index afc42ae..5c7c676 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -5,7 +5,7 @@ import csv # sys.path.append("./pytorchfi") -from ..pytorchfi.pytorchfi import core +from pytorchfi import core # from num_sys_class import * From 7c83baebe7722e1030dba7cf87526e1bef7b2681 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:56:12 -0400 Subject: [PATCH 23/48] Fixed get_curr_layer --- src/goldeneye.py | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 5c7c676..463e4f2 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -285,20 +285,20 @@ def _flip_bit_goldeneye(self, orig_value, max_value, bit_pos=-1, to_inj=False): def apply_goldeneye_transformation(self, module, input, output): corrupt_layer_set = self.get_corrupt_layer() - range_max = self.get_layer_max(self.get_current_layer()) + range_max = self.get_layer_max(self.get_curr_layer()) # Setting current num-sys for mixed-precision if type(self.num_sys) is list: (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[ - self.get_current_layer() + self.get_curr_layer() ] - logging.info("curr_conv", self.get_current_layer()) + logging.info("curr_conv", self.get_curr_layer()) logging.info("range_max", range_max) inj_list = list( filter( - lambda x: corrupt_layer_set[x] == self.get_current_layer(), + lambda x: corrupt_layer_set[x] == self.get_curr_layer(), range(len(corrupt_layer_set)), ) ) @@ -338,7 +338,7 @@ def apply_goldeneye_transformation(self, module, input, output): ) # meta injections (tensor level) - if self.get_current_layer() in corrupt_layer_set and self.inj_order == 2: + if self.get_curr_layer() in corrupt_layer_set and self.inj_order == 2: # print("META INJECTION") meta_inj_en = True else: @@ -361,7 +361,7 @@ def apply_goldeneye_transformation(self, module, input, output): # always do this before proceeding self.updateLayer() - if self.get_current_layer() >= self.get_total_layers(): + if self.get_curr_layer() >= self.get_total_layers(): self.reset_current_layer() # baseDevice = output.get_device() @@ -376,8 +376,8 @@ def apply_goldeneye_transformation(self, module, input, output): # ) # apply is too slow, we replaced it by tensor-operations-based functions - # print("Layer: ", self.get_current_layer(), ", Shape: ", output.dim(), ", Size: ", output.size()) - # print("Layer: ", self.get_current_layer(), "Value: ", output[-1][24][12][12]) + # print("Layer: ", self.get_curr_layer(), ", Shape: ", output.dim(), ", Size: ", output.size()) + # print("Layer: ", self.get_curr_layer(), "Value: ", output[-1][24][12][12]) # print("New Value:", output[-1][24][12][12]) # if self.use_cuda: From 15c929eebe545f8435a7806711880b147d17136a Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 10:57:35 -0400 Subject: [PATCH 24/48] goldeneye fixed import --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 463e4f2..ab9b64b 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -5,7 +5,7 @@ import csv # sys.path.append("./pytorchfi") -from pytorchfi import core +from ..pytorchfi.pytorchfi import core # from num_sys_class import * From d9179d9d3231ba7b435d643b3f3c0694a072e485 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 11:21:53 -0400 Subject: [PATCH 25/48] Added layer_max --- val/test_mixed_precision.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 7291ee4..3114141 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,6 +1,7 @@ from goldeneye.src.goldeneye import goldeneye from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 from ..src.num_sys_class import * +from ..src.preprocess import gather_min_max_per_layer import copy # from goldeneye.src.util import * @@ -29,6 +30,13 @@ def setup_class(self): self.images, self.labels = self.dataiter.next() + # Preprocessing to get layer_max + self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( + self.model1, + self.dataiter, + self.BATCH_SIZE, + ) + def test_uniform(self, params): # Prepare goldeneye models for inference @@ -39,6 +47,7 @@ def test_uniform(self, params): self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, + layer_max=self.layer_max, quant=True, inj_order=0, num_sys=getNumSysName(self.num_sys_name), @@ -53,6 +62,7 @@ def test_uniform(self, params): self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, + layer_max=self.layer_max, quant=True, inj_order=0, num_sys=getNumSysName(self.num_sys_name), From 2a90ff2048498473fc07670fd976379e0206a986 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 11:23:57 -0400 Subject: [PATCH 26/48] Fixed import preprocess --- src/preprocess.py | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/src/preprocess.py b/src/preprocess.py index 71a1d3e..3e5fdcb 100644 --- a/src/preprocess.py +++ b/src/preprocess.py @@ -1,13 +1,24 @@ -from util import * +from .util import * import torch.nn as nn from tqdm import tqdm activations = [] + + def save_activations(module, input, output): activations.append(output) -def gather_min_max_per_layer(model, data_iter, batch_size, precision="FP16", cuda_en=True, debug=False, verbose=False): + +def gather_min_max_per_layer( + model, + data_iter, + batch_size, + precision="FP16", + cuda_en=True, + debug=False, + verbose=False, +): global activations layer_max = torch.Tensor([]) layer_min = torch.Tensor([]) @@ -19,7 +30,6 @@ def gather_min_max_per_layer(model, data_iter, batch_size, precision="FP16", cud layer_max = layer_max.half() layer_min = layer_min.half() - # register forward hook to the model handles = [] for param in model.modules(): @@ -75,18 +85,26 @@ def gather_min_max_per_layer(model, data_iter, batch_size, precision="FP16", cud return layer_min, layer_max, actual_max -if __name__ == '__main__': + +if __name__ == "__main__": # read in cmd line args check_args(sys.argv[1:]) - if getDebug(): printArgs() + if getDebug(): + printArgs() # common variables name = getDNN() + "_" + getDataset() out_path = getOutputDir() + "/networkRanges/" + name + "/" # load data and model - dataiter = load_dataset(getDataset(), getBatchsize(), workers = getWorkers(), training=True, include_id=False) + dataiter = load_dataset( + getDataset(), + getBatchsize(), + workers=getWorkers(), + training=True, + include_id=False, + ) model = getNetwork(getDNN(), getDataset()) model.eval() torch.no_grad() @@ -111,4 +129,4 @@ def gather_min_max_per_layer(model, data_iter, batch_size, precision="FP16", cud for i in range(len(ranges)): outputString = "%d, %f\n" % (i, ranges[i]) f.write(outputString) - f.close() \ No newline at end of file + f.close() From 427362b78ac860322f3e8ca8ae85990887e495dc Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 11:29:51 -0400 Subject: [PATCH 27/48] copied get_max_layer from preporcess --- val/test_mixed_precision.py | 83 ++++++++++++++++++++++++++++++++++++- 1 file changed, 82 insertions(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 3114141..4ca90e4 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -1,7 +1,7 @@ from goldeneye.src.goldeneye import goldeneye from ..pytorchfi.test.unit_tests.util_test import helper_setUp_CIFAR10 from ..src.num_sys_class import * -from ..src.preprocess import gather_min_max_per_layer +from tqdm import tqdm import copy # from goldeneye.src.util import * @@ -113,5 +113,86 @@ def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): sys.exit("Number format not supported") +################################################################# +# From preprocess.py, had an error importing util so copying it +# here for the moment +# TODO: fix this +################################################################# +def gather_min_max_per_layer( + model, + data_iter, + batch_size, + precision="FP16", + cuda_en=True, + debug=False, + verbose=False, +): + global activations + layer_max = torch.Tensor([]) + layer_min = torch.Tensor([]) + + if cuda_en: + layer_max = layer_max.cuda() + layer_min = layer_min.cuda() + if precision == "FP16": + layer_max = layer_max.half() + layer_min = layer_min.half() + + # register forward hook to the model + handles = [] + for param in model.modules(): + if isinstance(param, nn.Conv2d) or isinstance(param, nn.Linear): + handles.append(param.register_forward_hook(save_activations)) + + # main loops to gather ranges + processed_elements = 0 + batch_num = 0 + + for input_data in tqdm(data_iter): + + # prepare the next batch for inference + images, labels = input_data + if cuda_en: + images = images.cuda() + labels = labels.cuda() + if precision == "FP16": + images = images.half() + + activations = [] # reset before every inference + model(images) # run an inference + + # Range gathering: iterate through each layer + + min_vals = ( + torch.Tensor(list(map(lambda layer: layer.min().item(), activations))) + .cuda() + .half() + ) + max_vals = ( + torch.Tensor(list(map(lambda layer: layer.max().item(), activations))) + .cuda() + .half() + ) + if batch_num == 0: + layer_max = max_vals + layer_min = min_vals + else: + layer_max = torch.max(layer_max, max_vals) + layer_min = torch.min(layer_min, min_vals) + + processed_elements += len(labels) + batch_num += 1 + torch.cuda.empty_cache() + + # remove hooks + for i in range(len(handles)): + handles[i].remove() + del activations + + actual_max = torch.max(torch.abs(layer_min), torch.abs(layer_max)) + + return layer_min, layer_max, actual_max + + if __name__ == "__main__": print("Testing mixed-precision...") From 04ca9486ab1f291bca4c9b39e02194c4edc9475a Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 3 Aug 2022 11:41:59 -0400 Subject: [PATCH 28/48] save activations fixed --- src/preprocess.py | 1 - val/test_mixed_precision.py | 7 +++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/preprocess.py b/src/preprocess.py index 3e5fdcb..fe3a2e2 100644 --- a/src/preprocess.py +++ b/src/preprocess.py @@ -2,7 +2,6 @@ import torch.nn as nn from tqdm import tqdm - activations = [] diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 4ca90e4..fa2392d 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -118,6 +118,13 @@ def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): # here for the moment # TODO: fix this ################################################################# +activations = [] + + +def save_activations(module, input, output): + activations.append(output) + + def gather_min_max_per_layer( model, data_iter, From f2a9df44d4e8b9a1b4dc070c2ecc13992f26f044 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 10:44:26 -0400 Subject: [PATCH 29/48] added input conversion to half --- val/test_mixed_precision.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index fa2392d..b0ed74f 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -29,6 +29,9 @@ def setup_class(self): self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() + self.images = self.images.to( + torch.HalfTensor if self.USE_GPU else torch.cuda.HalfTensor + ) # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( From 326e1cd4865c348b0f8c683c68db3f0d332d43bf Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 10:51:17 -0400 Subject: [PATCH 30/48] added input conversion to half 2 --- val/test_mixed_precision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index b0ed74f..503e42d 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -29,9 +29,6 @@ def setup_class(self): self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() - self.images = self.images.to( - torch.HalfTensor if self.USE_GPU else torch.cuda.HalfTensor - ) # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( @@ -75,6 +72,9 @@ def test_uniform(self, params): function=gmodel1.apply_goldeneye_transformation ) + if self.num_sys_name == "fp16": + self.images.half() + print("Testing uniform: ") print(inf_model2(self.images)) From 98be445b0c59dc4fcf47d18ed98c4ce1df639209 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 10:53:47 -0400 Subject: [PATCH 31/48] added input conversion to half 3 --- val/test_mixed_precision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 503e42d..3066386 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -20,7 +20,7 @@ def setup_class(self): self.WORKERS = 1 self.channels = 3 self.img_size = 32 - self.USE_GPU = False + self.USE_GPU = True self.model1, self.dataset = helper_setUp_CIFAR10(self.BATCH_SIZE, self.WORKERS) self.model1.eval() @@ -73,7 +73,7 @@ def test_uniform(self, params): ) if self.num_sys_name == "fp16": - self.images.half() + self.images = self.images.cuda.half() print("Testing uniform: ") print(inf_model2(self.images)) From 2a51b47659f15dfa6a419c9f2dfd6efaef078780 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 10:56:39 -0400 Subject: [PATCH 32/48] added input conversion to half 4 --- val/test_mixed_precision.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 3066386..f929884 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -20,7 +20,7 @@ def setup_class(self): self.WORKERS = 1 self.channels = 3 self.img_size = 32 - self.USE_GPU = True + self.USE_GPU = False self.model1, self.dataset = helper_setUp_CIFAR10(self.BATCH_SIZE, self.WORKERS) self.model1.eval() @@ -29,6 +29,7 @@ def setup_class(self): self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() + self.images = self.images.FloatTensor() # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( @@ -72,9 +73,6 @@ def test_uniform(self, params): function=gmodel1.apply_goldeneye_transformation ) - if self.num_sys_name == "fp16": - self.images = self.images.cuda.half() - print("Testing uniform: ") print(inf_model2(self.images)) From 3de9e32fbc2c2b9ce21f529d5e17316457a452ce Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 10:59:24 -0400 Subject: [PATCH 33/48] added input conversion to half 5 --- val/test_mixed_precision.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index f929884..1d317d0 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -29,7 +29,7 @@ def setup_class(self): self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() - self.images = self.images.FloatTensor() + self.images = self.images.float() # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( From 85cffb3c8b1b83ae447b02f7948732b4ff5510d4 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:08:13 -0400 Subject: [PATCH 34/48] added input conversion to half 6 --- val/test_mixed_precision.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 1d317d0..38d6b11 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -29,7 +29,8 @@ def setup_class(self): self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() - self.images = self.images.float() + + self.images = self.images.to("fp16") # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( From 53e0439d221e9b350807a7d8cb6a629e0813d81a Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:11:48 -0400 Subject: [PATCH 35/48] added input conversion to float 7 --- val/test_mixed_precision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 38d6b11..4a2cebf 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -26,11 +26,11 @@ def setup_class(self): self.model1.eval() self.model2 = copy.deepcopy(self.model1) - self.dataiter = iter(self.dataset) + self.dataiter = iter(self.dataset.float()) self.images, self.labels = self.dataiter.next() - self.images = self.images.to("fp16") + # self.images = self.images.float() # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( From d117e49e8887d6ef7dd61c7e8c05e742af139a31 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:15:09 -0400 Subject: [PATCH 36/48] added input conversion to float 8 --- val/test_mixed_precision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 4a2cebf..54e5e9c 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -26,11 +26,11 @@ def setup_class(self): self.model1.eval() self.model2 = copy.deepcopy(self.model1) - self.dataiter = iter(self.dataset.float()) + self.dataiter = iter(self.dataset) self.images, self.labels = self.dataiter.next() - # self.images = self.images.float() + self.images = self.images.float() # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( From 0119f922d8b679d6149e85e165c97de7c8197a18 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:18:34 -0400 Subject: [PATCH 37/48] added input conversion to float 9 --- val/test_mixed_precision.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 54e5e9c..687aa8e 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -30,13 +30,9 @@ def setup_class(self): self.images, self.labels = self.dataiter.next() - self.images = self.images.float() - # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( - self.model1, - self.dataiter, - self.BATCH_SIZE, + self.model1, self.dataiter, self.BATCH_SIZE, precision="fp32" ) def test_uniform(self, params): From 15edf01ef6139f4bdf222a95b38eee1dd855d4b9 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:20:31 -0400 Subject: [PATCH 38/48] added input conversion to float 10 --- val/test_mixed_precision.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 687aa8e..b314d64 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -32,7 +32,11 @@ def setup_class(self): # Preprocessing to get layer_max self.layer_min, self.layer_max, self.actual_max = gather_min_max_per_layer( - self.model1, self.dataiter, self.BATCH_SIZE, precision="fp32" + self.model1, + self.dataiter, + self.BATCH_SIZE, + precision="fp32", + cuda_en=self.USE_GPU, ) def test_uniform(self, params): From 6843049017891d1d637c3cfb08b32c4d861b5605 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:24:06 -0400 Subject: [PATCH 39/48] added input conversion to float 11 --- val/test_mixed_precision.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index b314d64..0365b07 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -50,7 +50,7 @@ def test_uniform(self, params): input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, layer_max=self.layer_max, - quant=True, + quant=False, inj_order=0, num_sys=getNumSysName(self.num_sys_name), ) @@ -65,7 +65,7 @@ def test_uniform(self, params): input_shape=[3, self.img_size, self.img_size], use_cuda=self.USE_GPU, layer_max=self.layer_max, - quant=True, + quant=False, inj_order=0, num_sys=getNumSysName(self.num_sys_name), ) From ef4084b95536efa2733374ed3ad0db2e924b9e93 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:25:58 -0400 Subject: [PATCH 40/48] fixed goldeneye reset_curr_layer --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index ab9b64b..bb227f1 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -362,7 +362,7 @@ def apply_goldeneye_transformation(self, module, input, output): # always do this before proceeding self.updateLayer() if self.get_curr_layer() >= self.get_total_layers(): - self.reset_current_layer() + self.reset_curr_layer() # baseDevice = output.get_device() # TO OPTIMIZE (??). Must move to CPU, then back to_device From 996e595cc821caf6ab86e41abcd834c9356c0010 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 5 Aug 2022 11:28:32 -0400 Subject: [PATCH 41/48] added mp to test model --- val/test_mixed_precision.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index 0365b07..d249682 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -67,7 +67,7 @@ def test_uniform(self, params): layer_max=self.layer_max, quant=False, inj_order=0, - num_sys=getNumSysName(self.num_sys_name), + num_sys=[getNumSysName(self.num_sys_name)] * 14, ) inf_model2 = gmodel1.declare_neuron_fi( @@ -75,10 +75,10 @@ def test_uniform(self, params): ) print("Testing uniform: ") - print(inf_model2(self.images)) + print(inf_model1(self.images)) print("Testing fake mixed: ") - print(inf_model1(self.images)) + print(inf_model2(self.images)) ################################################################# From 8dcd4b692ee96f3d362868a66e12205adc1c1036 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Wed, 17 Aug 2022 11:14:05 -0400 Subject: [PATCH 42/48] Added support for config list --- src/goldeneye.py | 30 +++++++++++---- src/num_sys_class.py | 73 +++++++++++++++++++++++++++++++++++++ val/test_mixed_precision.py | 42 ++------------------- 3 files changed, 99 insertions(+), 46 deletions(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index bb227f1..9f86ef5 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -1,4 +1,5 @@ import random, sys +import string import logging import numpy as np import torch @@ -6,6 +7,7 @@ # sys.path.append("./pytorchfi") from ..pytorchfi.pytorchfi import core +from .num_sys_class import * # from num_sys_class import * @@ -42,14 +44,8 @@ def __init__( # for simulated number system - # TODO: Handle two options (1: uniform quantization so self.num_sys is one num_sys, 2: List of number systems) - self.num_sys = num_sys - - if type(num_sys) is not list: - (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys - elif len(num_sys) == 1: - # List with only one numsys means we have uniform quantization across the network - (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[0] + # Processing input + self.process_numsys_input(num_sys) self.signed = kwargs.get("signed", True) @@ -61,6 +57,24 @@ def __init__( # the order of injecting within the goldeneye transformation # 0 -> no injection, 1 -> between quantization and de-quantization, 2 -> after converting to the number system, 3 -> after dequantization, 4 -> after converting num sys + def process_num_sys_input(self, num_sys): + # Options: + # 1. num_sys is a string + # 2. num_sys is a tuple (numsys_obj, name) + # 3. num_sys is a list of configurations or strings(eg. [("fp", 8, 23), "bfloat16",("fxp", 5, 10)]) + + if type(num_sys) is str: + (self.cur_num_sys, self.cur_num_sys_name) = string_to_numsys(self.num_sys) + self.num_sys = num_sys + elif type(num_sys) is tuple: # i.e one numsys_obj, name tuple + (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys + self.num_sys = num_sys + else: # type(num_sys) is list: + assert type(num_sys) is list + + self.num_sys = self.to_numsys_list(num_sys) + (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[0] + def set_layer_max(self, data): self.LayerRanges = data diff --git a/src/num_sys_class.py b/src/num_sys_class.py index 7c10838..674d950 100644 --- a/src/num_sys_class.py +++ b/src/num_sys_class.py @@ -1,3 +1,4 @@ +from nis import match import os import random import torch @@ -568,3 +569,75 @@ def quantize_adaptivfloat_meta(self, # Python # return self.quantize_adaptivfloat_meta_py(float_arr, n_bits, n_exp, bias) + +################################################################# +################### HELPER METHODS FOR NUMSYS ################### +################################################################# +def string_to_numsys(name, bits=16, radix_up=5, radix_down=10, bias=None): + # common number systems in PyTorch + if name == "fp32": + return num_fp32(), name + if name == "INT": + # assert getQuantize_en() + return num_fp32(), name + elif name == "fp16": + return num_fp16(), name + elif name == "bfloat16": + return num_bfloat16(), name + + # generic number systems in PyTorch + elif name == "fp_n": + return num_float_n(exp_len=radix_up, mant_len=radix_down), name + elif name == "fxp_n": + return num_fixed_pt(int_len=radix_up, frac_len=radix_down), name + elif name == "block_fp": + return block_fp(bit_width=bits, exp_len=radix_up, mant_len=radix_down), name + elif name == "adaptive_fp": + return ( + adaptive_float( + bit_width=bits, exp_len=radix_up, mant_len=radix_down, exp_bias=bias + ), + name, + ) + + else: + sys.exit("Config format error: Number format not supported") + +def config_to_numsys(config): + # check config format is correct + assert(type(config) is tuple) + + match config[0]: + case "fp32": + return num_fp32(), "fp32" + case "INT": + # assert getQuantize_en() + return num_fp32(), "INT" + case "fp16": + return num_fp16(), "fp16" + case "bfloat16": + return num_bfloat16(), "bfloat16" + case "fp": + return num_float_n(exp_len=config[1], mant_len=config[2]), "fp_n" + case "fxp": + return num_fixed_pt(int_len=config[1], frac_len=config[2]), "fxp_n" + case "block_fp": + return block_fp(bit_width=config[1], exp_len=config[2], mant_len=config[3]), "block_fp" + case "adaptive_fp": + return adaptive_float(bit_width=config[1], exp_len=config[2], mant_len=config[3], exp_bias=config[4]), "adaptive_fp" + case _: + raise Exception("Config format error: Number format not supported") + +def to_numsys_list(lst, conversion_func): + numsys_list = [] + for config in lst: + numsys_list.append(conversion_func(config)) + return numsys_list + +def string_list_to_numsys_list(config_list): + to_numsys_list(config_list, string_to_numsys) + +def config_list_to_numsys_list(config_list): + to_numsys_list(config_list, config_to_numsys) + + diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index d249682..e0470f9 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -39,7 +39,7 @@ def setup_class(self): cuda_en=self.USE_GPU, ) - def test_uniform(self, params): + def test_uniform_string_and_list_of_strings(self, params): # Prepare goldeneye models for inference self.num_sys_name = params["num_sys_name"] @@ -48,11 +48,11 @@ def test_uniform(self, params): self.model1, self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], + num_sys=self.num_sys_name, + quant=False, use_cuda=self.USE_GPU, layer_max=self.layer_max, - quant=False, inj_order=0, - num_sys=getNumSysName(self.num_sys_name), ) inf_model1 = gmodel1.declare_neuron_fi( @@ -63,11 +63,11 @@ def test_uniform(self, params): self.model2, self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], + num_sys=[self.num_sys_name] * 14, use_cuda=self.USE_GPU, layer_max=self.layer_max, quant=False, inj_order=0, - num_sys=[getNumSysName(self.num_sys_name)] * 14, ) inf_model2 = gmodel1.declare_neuron_fi( @@ -81,40 +81,6 @@ def test_uniform(self, params): print(inf_model2(self.images)) -################################################################# -################### HELPER METHODS FOR NUMSYS ################### -################################################################# -def getNumSysName(name, bits=16, radix_up=5, radix_down=10, bias=None): - # common number systems in PyTorch - if name == "fp32": - return num_fp32(), name - if name == "INT": - # assert getQuantize_en() - return num_fp32(), name - elif name == "fp16": - return num_fp16(), name - elif name == "bfloat16": - return num_bfloat16(), name - - # generic number systems in PyTorch - elif name == "fp_n": - return num_float_n(exp_len=radix_up, mant_len=radix_down), name - elif name == "fxp_n": - return num_fixed_pt(int_len=radix_up, frac_len=radix_down), name - elif name == "block_fp": - return block_fp(bit_width=bits, exp_len=radix_up, mant_len=radix_down), name - elif name == "adaptive_fp": - return ( - adaptive_float( - bit_width=bits, exp_len=radix_up, mant_len=radix_down, exp_bias=bias - ), - name, - ) - - else: - sys.exit("Number format not supported") - - ################################################################# # From preprocess.py, had an error importing util so copying it # here for the moment From 5012406c96f3ff89b61ce5044162aea363680b67 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 19 Aug 2022 10:45:49 -0400 Subject: [PATCH 43/48] switch match to if statement --- src/num_sys_class.py | 226 +++++++++++++++++++++++++------------------ 1 file changed, 134 insertions(+), 92 deletions(-) diff --git a/src/num_sys_class.py b/src/num_sys_class.py index 674d950..c005c58 100644 --- a/src/num_sys_class.py +++ b/src/num_sys_class.py @@ -12,7 +12,7 @@ sources=[ os.path.join(current_path, "num_sys.cpp"), os.path.join(current_path, "num_sys_helper.cpp"), - ] + ], ) @@ -20,6 +20,7 @@ class _number_sys: """ General class for number systems, used to bit_flip using a specific format """ + def bit_flip(self, bit_arr, bit_ind): # interpret index from least significant bit bit_ind_LSB = len(bit_arr) - 1 - bit_ind @@ -109,14 +110,9 @@ def bin_to_frac(frac_str): class _ieee754(_number_sys): """IEEE Standard 754 Floating Point Number System""" + def __init__( - self, - exp_len=8, - mant_len=23, - bias=None, - denorm=True, - max_val=None, - min_val=None + self, exp_len=8, mant_len=23, bias=None, denorm=True, max_val=None, min_val=None ): self.exp_len = exp_len self.mant_len = mant_len @@ -151,13 +147,13 @@ def real_to_format(self, num): if int_str.find("1") != -1: # decimal shift ind = len(int_str) - 1 - int_str.index("1") - int_str = int_str[len(int_str) - ind - 1:] + int_str = int_str[len(int_str) - ind - 1 :] exp_str = _number_sys.int_to_bin(ind + self.bias) else: if frac_str.find("1") != -1: dec_shift = frac_str.index("1") + 1 if dec_shift > self.bias: - frac_str = frac_str[self.bias:] + frac_str = frac_str[self.bias :] else: exp_str = _number_sys.int_to_bin(-dec_shift + self.bias) frac_str = frac_str[dec_shift:] @@ -168,10 +164,14 @@ def real_to_format(self, num): mant_str = (mant_str + ("0" * (self.mant_len - len(mant_str))))[: self.mant_len] # asserts - assert len(exp_str) == self.exp_len,\ - "exp_len unknown error: %d != %d" %(len(exp_str), self.exp_len) - assert len(mant_str) == self.mant_len,\ - "mant_len unknown error: %d != %d" %(len(mant_str), self.mant_str) + assert len(exp_str) == self.exp_len, "exp_len unknown error: %d != %d" % ( + len(exp_str), + self.exp_len, + ) + assert len(mant_str) == self.mant_len, "mant_len unknown error: %d != %d" % ( + len(mant_str), + self.mant_str, + ) return list("".join([sign, exp_str, mant_str])) @@ -186,19 +186,19 @@ def mant_to_int(mantissa_str): sign = pow(-1, int(bit_arr[0])) - exp_str = "".join(bit_arr[1:self.exp_len + 1]) + exp_str = "".join(bit_arr[1 : self.exp_len + 1]) exp = int(exp_str, 2) - self.bias - mant_str = "".join(bit_arr[self.exp_len + 1:]) + mant_str = "".join(bit_arr[self.exp_len + 1 :]) mant = mant_to_int(mant_str) # exceptions if exp_str == "0" * self.exp_len and mant_str == "0" * self.mant_len: return 0 if exp_str == "1" * self.exp_len and mant_str == "0" * self.mant_len: - return sign * float('inf') + return sign * float("inf") if exp_str == "1" * self.exp_len and mant_str != "0" * self.mant_len: - return float('nan') + return float("nan") # handling denormals if exp_str == "0" * self.exp_len and mant_str != "0" * self.mant_len: @@ -224,13 +224,14 @@ def int_to_bitstream(self, num): return list(int_str) def bitstream_to_int(self, bit_arr): - exp_str = "".join(bit_arr[1: self.exp_len + 1]) + exp_str = "".join(bit_arr[1 : self.exp_len + 1]) exp = int(exp_str, 2) return exp class num_fp32(_ieee754): """Floating Point 32 Number System""" + def __init__(self): super(num_fp32, self).__init__() @@ -240,6 +241,7 @@ def real_to_format_tensor(self, tensor): class num_fp16(_ieee754): """Floating Point 16 Number System""" + def __init__(self): super(num_fp16, self).__init__(exp_len=5, mant_len=10) @@ -249,6 +251,7 @@ def real_to_format_tensor(self, tensor): class num_float_n(_ieee754): """Floating Point Number System""" + # 1 bit for sign + len(integer part) + len(frac part) def __init__(self, exp_len=5, mant_len=10): super(num_float_n, self).__init__(exp_len=exp_len, mant_len=mant_len) @@ -259,6 +262,7 @@ def real_to_format_tensor(self, tensor): class num_bfloat16(_ieee754): """Brain Float Number System""" + def __init__(self): super(num_bfloat16, self).__init__(exp_len=8, mant_len=7) @@ -268,6 +272,7 @@ def real_to_format_tensor(self, tensor): class num_fixed_pt(_number_sys): """Fixed Point Number System""" + # 1 bit for sign + len(integer part) + len(frac part) def __init__(self, int_len=3, frac_len=3): self.int_len = int_len @@ -281,7 +286,7 @@ def real_to_format(self, num): if len(int_str) > self.int_len: int_str = "1" * self.int_len - frac_str = _number_sys.frac_to_bin(num - int(num))[:self.frac_len] + frac_str = _number_sys.frac_to_bin(num - int(num))[: self.frac_len] # zero padding int_str = ("0" * (self.int_len - len(int_str))) + int_str @@ -290,34 +295,36 @@ def real_to_format(self, num): return list(sign) + list(int_str) + list(frac_str) def real_to_format_tensor(self, tensor): - return fixed_point_quantize(tensor, - 1 + self.int_len + self.frac_len, - self.frac_len) + return fixed_point_quantize( + tensor, 1 + self.int_len + self.frac_len, self.frac_len + ) def format_to_real(self, bit_arr): - int_str, frac_str = map(lambda arr: "".join(arr), - (bit_arr[1:self.int_len + 1], - bit_arr[self.int_len + 1:]),) + int_str, frac_str = map( + lambda arr: "".join(arr), + (bit_arr[1 : self.int_len + 1], bit_arr[self.int_len + 1 :]), + ) sign = 1 if bit_arr[0] == "0" else -1 return sign * (int(int_str, 2) + _number_sys.bin_to_frac(frac_str)) class block_fp(_ieee754): """Block Float Number System""" + # 1 bit for sign + len(integer part) + len(frac part) def __init__(self, bit_width=32, exp_len=8, mant_len=23): super(block_fp, self).__init__(exp_len=exp_len, mant_len=mant_len) self.bit_width = bit_width def real_to_format_tensor(self, tensor): - return self.quant_bfloat(float_arr=tensor, - n_bits=self.bit_width, - n_exp=self.exp_len) + return self.quant_bfloat( + float_arr=tensor, n_bits=self.bit_width, n_exp=self.exp_len + ) def real_to_format_tensor_meta(self, tensor): - return self.quant_bfloat_meta(float_arr=tensor, - n_bits=self.bit_width, - n_exp=self.exp_len) + return self.quant_bfloat_meta( + float_arr=tensor, n_bits=self.bit_width, n_exp=self.exp_len + ) def quant_bfloat_py(self, float_arr, n_bits, n_exp): n_mant = n_bits - 1 - n_exp @@ -326,11 +333,11 @@ def quant_bfloat_py(self, float_arr, n_bits, n_exp): float_arr = torch.abs(float_arr) # 2. limits the range of output float point - min_exp = -2 ** (n_exp - 1) + 2 + min_exp = -(2 ** (n_exp - 1)) + 2 max_exp = 2 ** (n_exp - 1) - 1 - min_value = 2 ** min_exp - max_value = (2 ** max_exp) * (2 - 2 ** (-n_mant)) + min_value = 2**min_exp + max_value = (2**max_exp) * (2 - 2 ** (-n_mant)) # non-denormal part float_arr[float_arr < min_value] = 0 @@ -354,7 +361,7 @@ def quant_bfloat_py(self, float_arr, n_bits, n_exp): exp_adj = torch.full(exp.shape, shared_exp, device=float_arr.device) # exp should not be larger than max_exp - assert (shared_exp <= max_exp) + assert shared_exp <= max_exp power_exp = torch.exp2(exp_adj) # 4. quantize mantissa @@ -378,11 +385,11 @@ def quant_bfloat_meta_py(self, float_arr, n_bits=8, n_exp=3): float_arr = torch.abs(float_arr) # 2. limits the range of output float point - min_exp = -2 ** (n_exp - 1) + 2 + min_exp = -(2 ** (n_exp - 1)) + 2 max_exp = 2 ** (n_exp - 1) - 1 - min_value = 2 ** min_exp - max_value = (2 ** max_exp) * (2 - 2 ** (-n_mant)) + min_value = 2**min_exp + max_value = (2**max_exp) * (2 - 2 ** (-n_mant)) # non-denormal part float_arr[float_arr < min_value] = 0 @@ -419,7 +426,7 @@ def quant_bfloat_meta_py(self, float_arr, n_bits=8, n_exp=3): exp_adj = torch.full(exp.shape, shared_exp, device=float_arr.device) # exp should not be larger than max_exp - assert (shared_exp <= max_exp) + assert shared_exp <= max_exp power_exp = torch.exp2(exp_adj) # 4. quantize mantissa @@ -439,6 +446,7 @@ def quant_bfloat_meta(self, float_arr, n_bits=8, n_exp=3): class adaptive_float(_ieee754): """Adaptive Float Number System""" + # 1 bit for sign + len(integer part) + len(frac part) def __init__(self, bit_width=32, exp_len=8, mant_len=23, exp_bias=None): super(adaptive_float, self).__init__(exp_len=exp_len, mant_len=mant_len) @@ -446,16 +454,20 @@ def __init__(self, bit_width=32, exp_len=8, mant_len=23, exp_bias=None): self.exp_bias = exp_bias def real_to_format_tensor(self, tensor): - return self.quantize_adaptivfloat(float_arr=tensor, - n_bits=self.bit_width, - n_exp=self.exp_len, - bias=self.exp_bias) + return self.quantize_adaptivfloat( + float_arr=tensor, + n_bits=self.bit_width, + n_exp=self.exp_len, + bias=self.exp_bias, + ) def real_to_format_tensor_meta(self, tensor): - return self.quantize_adaptivfloat_meta(float_arr=tensor, - n_bits=self.bit_width, - n_exp=self.exp_len, - bias=self.exp_bias) + return self.quantize_adaptivfloat_meta( + float_arr=tensor, + n_bits=self.bit_width, + n_exp=self.exp_len, + bias=self.exp_bias, + ) def quantize_adaptivfloat_py(self, float_arr, n_bits=8, n_exp=4, bias=None): n_mant = n_bits - 1 - n_exp @@ -467,11 +479,11 @@ def quantize_adaptivfloat_py(self, float_arr, n_bits=8, n_exp=4, bias=None): bias = (2 ** (n_exp - 1) - 1) - bias_temp # 2. limits the range of output float point - min_exp = -2 ** (n_exp - 1) + 2 - bias + min_exp = -(2 ** (n_exp - 1)) + 2 - bias max_exp = 2 ** (n_exp - 1) - 1 - bias - min_value = 2. ** min_exp - max_value = (2. ** max_exp) * (2 - 2 ** (-n_mant)) + min_value = 2.0**min_exp + max_value = (2.0**max_exp) * (2 - 2 ** (-n_mant)) # non-denormal part float_arr[float_arr < min_value] = 0 @@ -505,11 +517,7 @@ def quantize_adaptivfloat(self, float_arr, n_bits=8, n_exp=4, bias=None): # Python # return self.quantize_adaptivfloat_py(float_arr, n_bits, n_exp, bias) - def quantize_adaptivfloat_meta_py(self, - float_arr, - n_bits=8, - n_exp=4, - bias=None): + def quantize_adaptivfloat_meta_py(self, float_arr, n_bits=8, n_exp=4, bias=None): n_mant = n_bits - 1 - n_exp # 1. store sign value and do the following part as unsigned value sign = torch.sign(float_arr) @@ -531,11 +539,11 @@ def quantize_adaptivfloat_meta_py(self, # ============= ERROR INJECTION INTO META ============= # 2. limits the range of output float point - min_exp = -2 ** (n_exp - 1) + 2 - bias + min_exp = -(2 ** (n_exp - 1)) + 2 - bias max_exp = 2 ** (n_exp - 1) - 1 - bias - min_value = 2. ** min_exp - max_value = (2. ** max_exp) * (2 - 2 ** (-n_mant)) + min_value = 2.0**min_exp + max_value = (2.0**max_exp) * (2 - 2 ** (-n_mant)) # non-denormal part float_arr[float_arr < min_value] = 0 @@ -559,21 +567,20 @@ def quantize_adaptivfloat_meta_py(self, float_out = sign * power_exp * mant return float_out - def quantize_adaptivfloat_meta(self, - float_arr, - n_bits=8, - n_exp=4, - bias=None): + def quantize_adaptivfloat_meta(self, float_arr, n_bits=8, n_exp=4, bias=None): # C++ return num_sys.quantize_adaptivfloat_meta(float_arr, n_bits, n_exp, -1) # Python # return self.quantize_adaptivfloat_meta_py(float_arr, n_bits, n_exp, bias) + ################################################################# ################### HELPER METHODS FOR NUMSYS ################### ################################################################# def string_to_numsys(name, bits=16, radix_up=5, radix_down=10, bias=None): + ## DESC: convert string name to numsys + # common number systems in PyTorch if name == "fp32": return num_fp32(), name @@ -603,41 +610,76 @@ def string_to_numsys(name, bits=16, radix_up=5, radix_down=10, bias=None): else: sys.exit("Config format error: Number format not supported") + def config_to_numsys(config): + ## DESC: converts a configuration (eg. ("fp", 8, 23) to a number system object + # check config format is correct - assert(type(config) is tuple) - - match config[0]: - case "fp32": - return num_fp32(), "fp32" - case "INT": - # assert getQuantize_en() - return num_fp32(), "INT" - case "fp16": - return num_fp16(), "fp16" - case "bfloat16": - return num_bfloat16(), "bfloat16" - case "fp": - return num_float_n(exp_len=config[1], mant_len=config[2]), "fp_n" - case "fxp": - return num_fixed_pt(int_len=config[1], frac_len=config[2]), "fxp_n" - case "block_fp": - return block_fp(bit_width=config[1], exp_len=config[2], mant_len=config[3]), "block_fp" - case "adaptive_fp": - return adaptive_float(bit_width=config[1], exp_len=config[2], mant_len=config[3], exp_bias=config[4]), "adaptive_fp" - case _: - raise Exception("Config format error: Number format not supported") - -def to_numsys_list(lst, conversion_func): + assert type(config) is tuple + + if config[0] is "fp32": + return num_fp32(), "fp32" + elif config[0] is "INT": + # assert getQuantize_en() + return num_fp32(), "INT" + elif config[0] is "fp16": + return num_fp16(), "fp16" + elif config[0] is "bfloat16": + return num_bfloat16(), "bfloat16" + elif config[0] is "fp": + return num_float_n(exp_len=config[1], mant_len=config[2]), "fp_n" + elif config[0] is "fxp": + return num_fixed_pt(int_len=config[1], frac_len=config[2]), "fxp_n" + elif config[0] is "block_fp": + return ( + block_fp(bit_width=config[1], exp_len=config[2], mant_len=config[3]), + "block_fp", + ) + elif config[0] is "adaptive_fp": + return ( + adaptive_float( + bit_width=config[1], + exp_len=config[2], + mant_len=config[3], + exp_bias=config[4], + ), + "adaptive_fp", + ) + else: + raise Exception("Config format error: Number format not supported") + + +def to_numsys_list_func(lst, conversion_func): + ## DESC: converts a list of numsys descriptions (string name or config tuple) to a list of numsys objects + ######## based on a fixed conversion function + + # Check list is not empty + assert len(lst) > 0 + numsys_list = [] for config in lst: numsys_list.append(conversion_func(config)) return numsys_list + +def to_numsys_list(lst): + ## DESC: converts a list of numsys descriptions (string name or config tuple) to a list of numsys objects + + # Check list is not empty + assert len(lst) > 0 + + numsys_list = [] + for config in lst: + conversion_func = string_to_numsys if type(config) is str else config_to_numsys + numsys_list.append(conversion_func(config)) + return numsys_list + + def string_list_to_numsys_list(config_list): - to_numsys_list(config_list, string_to_numsys) + ## DESC: converts a list of numsys string names to a list of numsys objects + to_numsys_list_func(config_list, string_to_numsys) -def config_list_to_numsys_list(config_list): - to_numsys_list(config_list, config_to_numsys) - +def config_list_to_numsys_list(config_list): + ## DESC: converts a list of numsys config tuples to a list of numsys objects + to_numsys_list_func(config_list, config_to_numsys) From 66a24d612a85ae7c7e4a02fd1e182d46c79925f7 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 19 Aug 2022 10:47:48 -0400 Subject: [PATCH 44/48] switch is by == --- src/num_sys_class.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/num_sys_class.py b/src/num_sys_class.py index c005c58..af91646 100644 --- a/src/num_sys_class.py +++ b/src/num_sys_class.py @@ -615,27 +615,27 @@ def config_to_numsys(config): ## DESC: converts a configuration (eg. ("fp", 8, 23) to a number system object # check config format is correct - assert type(config) is tuple + assert type(config) == tuple - if config[0] is "fp32": + if config[0] == "fp32": return num_fp32(), "fp32" - elif config[0] is "INT": + elif config[0] == "INT": # assert getQuantize_en() return num_fp32(), "INT" - elif config[0] is "fp16": + elif config[0] == "fp16": return num_fp16(), "fp16" - elif config[0] is "bfloat16": + elif config[0] == "bfloat16": return num_bfloat16(), "bfloat16" - elif config[0] is "fp": + elif config[0] == "fp": return num_float_n(exp_len=config[1], mant_len=config[2]), "fp_n" - elif config[0] is "fxp": + elif config[0] == "fxp": return num_fixed_pt(int_len=config[1], frac_len=config[2]), "fxp_n" - elif config[0] is "block_fp": + elif config[0] == "block_fp": return ( block_fp(bit_width=config[1], exp_len=config[2], mant_len=config[3]), "block_fp", ) - elif config[0] is "adaptive_fp": + elif config[0] == "adaptive_fp": return ( adaptive_float( bit_width=config[1], From bdf530b04c5c5384526b180c381ffad4bd8bff00 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 19 Aug 2022 10:54:55 -0400 Subject: [PATCH 45/48] error fix --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 9f86ef5..2b8190c 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -57,7 +57,7 @@ def __init__( # the order of injecting within the goldeneye transformation # 0 -> no injection, 1 -> between quantization and de-quantization, 2 -> after converting to the number system, 3 -> after dequantization, 4 -> after converting num sys - def process_num_sys_input(self, num_sys): + def process_numsys_input(self, num_sys): # Options: # 1. num_sys is a string # 2. num_sys is a tuple (numsys_obj, name) From 8bca0d4af1a3bcf5abe675fd12915426ce8e2093 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 19 Aug 2022 10:56:34 -0400 Subject: [PATCH 46/48] error fix 2 --- src/goldeneye.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index 2b8190c..bf0d76a 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -64,10 +64,10 @@ def process_numsys_input(self, num_sys): # 3. num_sys is a list of configurations or strings(eg. [("fp", 8, 23), "bfloat16",("fxp", 5, 10)]) if type(num_sys) is str: - (self.cur_num_sys, self.cur_num_sys_name) = string_to_numsys(self.num_sys) + (self.cur_num_sys, self.cur_num_sys_name) = string_to_numsys(num_sys) self.num_sys = num_sys elif type(num_sys) is tuple: # i.e one numsys_obj, name tuple - (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys + (self.cur_num_sys, self.cur_num_sys_name) = num_sys self.num_sys = num_sys else: # type(num_sys) is list: assert type(num_sys) is list From 6a6675b97db3b1c1779bf1c5c4f03131ce4965cd Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Fri, 19 Aug 2022 10:58:13 -0400 Subject: [PATCH 47/48] error fix 3 --- src/goldeneye.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/goldeneye.py b/src/goldeneye.py index bf0d76a..6c0a70d 100644 --- a/src/goldeneye.py +++ b/src/goldeneye.py @@ -72,7 +72,7 @@ def process_numsys_input(self, num_sys): else: # type(num_sys) is list: assert type(num_sys) is list - self.num_sys = self.to_numsys_list(num_sys) + self.num_sys = to_numsys_list(num_sys) (self.cur_num_sys, self.cur_num_sys_name) = self.num_sys[0] def set_layer_max(self, data): From b5dd5356ccc68f5e4d92cfe1aefd3bebbcf381d6 Mon Sep 17 00:00:00 2001 From: Tarek Aloui Date: Tue, 30 Aug 2022 00:37:05 -0400 Subject: [PATCH 48/48] more tests needed --- val/test_mixed_precision.py | 47 +++++++++++++++++++++++++++++++++---- 1 file changed, 43 insertions(+), 4 deletions(-) diff --git a/val/test_mixed_precision.py b/val/test_mixed_precision.py index e0470f9..61ec301 100644 --- a/val/test_mixed_precision.py +++ b/val/test_mixed_precision.py @@ -39,16 +39,15 @@ def setup_class(self): cuda_en=self.USE_GPU, ) - def test_uniform_string_and_list_of_strings(self, params): + def test_diff_string_and_list_of_strings(self): # Prepare goldeneye models for inference - self.num_sys_name = params["num_sys_name"] gmodel1 = goldeneye( self.model1, self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], - num_sys=self.num_sys_name, + num_sys="fp32", quant=False, use_cuda=self.USE_GPU, layer_max=self.layer_max, @@ -63,7 +62,47 @@ def test_uniform_string_and_list_of_strings(self, params): self.model2, self.BATCH_SIZE, input_shape=[3, self.img_size, self.img_size], - num_sys=[self.num_sys_name] * 14, + num_sys=["fp32"] * 14, + use_cuda=self.USE_GPU, + layer_max=self.layer_max, + quant=False, + inj_order=0, + ) + + inf_model2 = gmodel1.declare_neuron_fi( + function=gmodel1.apply_goldeneye_transformation + ) + + print("Testing uniform: ") + print(inf_model1(self.images)) + + print("Testing fake mixed: ") + print(inf_model2(self.images)) + + def test_uniform_string_list_of_configs(self, params): + + # Prepare goldeneye models for inference + + gmodel1 = goldeneye( + self.model1, + self.BATCH_SIZE, + input_shape=[3, self.img_size, self.img_size], + num_sys="fp32", + quant=False, + use_cuda=self.USE_GPU, + layer_max=self.layer_max, + inj_order=0, + ) + + inf_model1 = gmodel1.declare_neuron_fi( + function=gmodel1.apply_goldeneye_transformation + ) + + gmodel2 = goldeneye( + self.model2, + self.BATCH_SIZE, + input_shape=[3, self.img_size, self.img_size], + num_sys=[("fp", 5, 10), ("fxp", 4, 10)] * 7, use_cuda=self.USE_GPU, layer_max=self.layer_max, quant=False,