def test_compare_model_outputs_conv_static(self): r"""Compare the output of conv layer in stataic quantized model and corresponding output of conv layer in float model """ qengine = torch.backends.quantized.engine def compare_and_validate_results(float_model, q_model, data): act_compare_dict = compare_model_outputs(float_model, q_model, data) expected_act_compare_dict_keys = {"conv.stats", "quant.stats"} self.assertTrue( act_compare_dict.keys() == expected_act_compare_dict_keys) for k, v in act_compare_dict.items(): self.assertTrue(v["float"][0].shape == v["quantized"][0].shape) model_list = [ AnnotatedConvModel(qengine), AnnotatedConvBnReLUModel(qengine) ] for model in model_list: model.eval() if hasattr(model, "fuse_model"): model.fuse_model() q_model = quantize(model, test_only_eval_fn, [self.img_data_2d]) compare_and_validate_results(model, q_model, self.img_data_2d[0][0])
def test_compare_model_outputs_linear_static(self): r"""Compare the output of linear layer in static quantized model and corresponding output of conv layer in float model """ qengine = torch.backends.quantized.engine def compare_and_validate_results(float_model, q_model, data): act_compare_dict = compare_model_outputs(float_model, q_model, data) expected_act_compare_dict_keys = { "fc1.quant.stats", "fc1.module.stats" } self.assertTrue( act_compare_dict.keys() == expected_act_compare_dict_keys) for k, v in act_compare_dict.items(): self.assertTrue(len(v["float"]) == len(v["quantized"])) for i, val in enumerate(v["quantized"]): self.assertTrue( v["float"][i].shape == v["quantized"][i].shape) linear_data = self.calib_data[0][0] model_list = [AnnotatedSingleLayerLinearModel(qengine)] for model in model_list: model.eval() if hasattr(model, "fuse_model"): model.fuse_model() q_model = quantize(model, test_only_eval_fn, [self.calib_data]) compare_and_validate_results(model, q_model, linear_data)
def test_compare_model_stub_partial(self): r"""Compare the output of static quantized linear layer and its float shadow module""" qengine = torch.backends.quantized.engine # TODO: Rebase on top of PR to remove compare and validate results here def compare_and_validate_results(float_model, q_model, module_swap_list, data): ob_dict = compare_model_stub(float_model, q_model, module_swap_list, data) self.assertEqual(len(ob_dict), 1) for k, v in ob_dict.items(): self.assertTrue(len(v["float"]) == len(v["quantized"])) for i, val in enumerate(v["quantized"]): self.assertTrue( v["float"][i].shape == v["quantized"][i].shape) linear_data = self.calib_data[0][0] module_swap_list = [nn.Linear] model_list = [AnnotatedTwoLayerLinearModel()] for model in model_list: model.eval() if hasattr(model, "fuse_model"): model.fuse_model() q_model = quantize(model, test_only_eval_fn, [self.calib_data]) compare_and_validate_results(model, q_model, module_swap_list, linear_data)
def test_compare_model_stub_conv_static(self): r"""Compare the output of static quantized conv layer and its float shadow module""" qengine = torch.backends.quantized.engine def compare_and_validate_results(float_model, q_model, module_swap_list, data): ob_dict = compare_model_stub(float_model, q_model, module_swap_list, data) self.assertEqual(len(ob_dict), 1) for k, v in ob_dict.items(): self.assertTrue(len(v["float"]) == len(v["quantized"])) for i, val in enumerate(v["quantized"]): self.assertTrue( v["float"][i].shape == v["quantized"][i].shape) model_list = [ AnnotatedConvModel(qengine), AnnotatedConvTransposeModel( "qnnpack"), # ConvT cannot use per channel weights AnnotatedConvBnReLUModel(qengine) ] module_swap_list = [ nn.Conv2d, nn.intrinsic.modules.fused.ConvReLU2d, nn.ConvTranspose2d ] for model in model_list: model.eval() if hasattr(model, "fuse_model"): model.fuse_model() q_model = quantize(model, test_only_eval_fn, [self.img_data_2d]) compare_and_validate_results(model, q_model, module_swap_list, self.img_data_2d[0][0])
def test_compare_model_stub_submodule_static(self): r"""Compare the output of static quantized submodule and its float shadow module""" qengine = torch.backends.quantized.engine model = ModelWithSubModules().eval() q_model = quantize(model, test_only_eval_fn, [self.img_data_2d]) module_swap_list = [SubModule, nn.Conv2d] ob_dict = compare_model_stub(model, q_model, module_swap_list, self.img_data_2d[0][0]) # Since conv is not quantized, we do not insert a shadow module # mod1 contains a linear that is quantized, so we insert a shadow module self.assertTrue(isinstance(q_model.mod1, Shadow)) self.assertFalse(isinstance(q_model.conv, Shadow))
def test_compare_weights_linear_static(self): r"""Compare the weights of float and static quantized linear layer""" qengine = torch.backends.quantized.engine def compare_and_validate_results(float_model, q_model): weight_dict = compare_weights(float_model.state_dict(), q_model.state_dict()) self.assertEqual(len(weight_dict), 1) for k, v in weight_dict.items(): self.assertTrue(v["float"].shape == v["quantized"].shape) model_list = [AnnotatedSingleLayerLinearModel(qengine)] for model in model_list: model.eval() if hasattr(model, "fuse_model"): model.fuse_model() q_model = quantize(model, test_only_eval_fn, [self.calib_data]) compare_and_validate_results(model, q_model)
def _test_vision_model(self, float_model): float_model.to('cpu') float_model.eval() float_model.fuse_model() float_model.qconfig = torch.quantization.default_qconfig img_data = [(torch.rand(2, 3, 224, 224, dtype=torch.float), torch.randint(0, 1, (2, ), dtype=torch.long)) for _ in range(2)] qmodel = quantize(float_model, torch.quantization.default_eval_fn, [img_data], inplace=False) wt_compare_dict = compare_weights(float_model.state_dict(), qmodel.state_dict()) def compute_error(x, y): Ps = torch.norm(x) Pn = torch.norm(x - y) return 20 * torch.log10(Ps / Pn) data = img_data[0][0] # Take in floating point and quantized model as well as input data, and returns a dict, with keys # corresponding to the quantized module names and each entry being a dictionary with two keys 'float' and # 'quantized', containing the activations of floating point and quantized model at matching locations. act_compare_dict = compare_model_outputs(float_model, qmodel, data) for key in act_compare_dict: compute_error(act_compare_dict[key]['float'][0], act_compare_dict[key]['quantized'][0].dequantize()) prepare_model_outputs(float_model, qmodel) for data in img_data: float_model(data[0]) qmodel(data[0]) # Find the matching activation between floating point and quantized modules, and return a dict with key # corresponding to quantized module names and each entry being a dictionary with two keys 'float' # and 'quantized', containing the matching floating point and quantized activations logged by the logger act_compare_dict = get_matching_activations(float_model, qmodel)
def test_fuse_module_eval(self): model = ModelForFusion(default_qconfig) model.eval() model = fuse_modules( model, [['conv3', 'bn3', 'relu4'], ['conv1', 'bn1', 'relu1'], ['conv2', 'relu2'], ['bn2', 'relu3'], ['sub1.conv', 'sub1.bn']]) self.assertEqual( type(model.conv1), nni.ConvReLU2d, msg="Fused Conv + BN + Relu first layer (BN is folded)") self.assertEqual(type(model.conv1[0]), nn.Conv2d, msg="Fused Conv + BN + Relu (Conv + folded BN only)") self.assertEqual(type(model.conv1[1]), nn.ReLU, msg="Fused Conv + BN + Relu second layer (Relu only)") self.assertEqual( type(model.bn1), nn.Identity, msg="Fused Conv + BN + Relu second layer (Skipped BN)") self.assertEqual( type(model.relu1), nn.Identity, msg="Fused Conv + BN + Relu second layer (Skipped Relu)") self.assertEqual( type(model.conv2), nni.ConvReLU3d, msg="Fused Conv + BN + Relu first layer (BN is folded)") self.assertEqual(type(model.bn2), nni.BNReLU3d, msg="Fused BN + Relu first layer (Relu is folded))") self.assertEqual(type(model.relu3), nn.Identity, msg="Fused BN + Relu second layer (Skipped Relu)") self.assertEqual(type(model.conv2[0]), nn.Conv3d, msg="Fused Conv + BN + Relu (Conv + folded BN only)") self.assertEqual(type(model.conv2[1]), nn.ReLU, msg="Fused Conv + BN + Relu second layer (Relu only)") self.assertEqual( type(model.relu2), nn.Identity, msg="Fused Conv + BN + Relu second layer (Skipped Relu)") self.assertEqual(type(model.conv3), nni.ConvReLU1d, msg="Fused Conv + Relu for Conv1d (folded BN)") self.assertEqual(type(model.conv3[0]), nn.Conv1d, msg="Fused Conv + Relu for Conv1d ") self.assertEqual(type(model.conv3[1]), nn.ReLU, msg="Fused Conv + Relu for Conv1d") self.assertEqual(type(model.bn3), nn.Identity, msg="Fused Conv + BN + Relu for Conv1d (Skipped BN)") self.assertEqual(type(model.sub1.conv), nn.Conv2d, msg="Fused submodule Conv + folded BN") self.assertEqual(type(model.sub1.bn), nn.Identity, msg="Fused submodule (skipped BN)") self.assertEqual(type(model.sub2.conv), nn.Conv2d, msg="Non-fused submodule Conv") self.assertEqual(type(model.sub2.relu), torch.nn.ReLU, msg="Non-fused submodule ReLU") model = prepare(model) self.checkObservers(model) test_only_eval_fn(model, self.img_data_1d) model = convert(model) def checkQuantized(model): self.assertEqual(type(model.conv3), nniq.ConvReLU1d) self.assertEqual(type(model.conv1), nniq.ConvReLU2d) self.assertEqual(type(model.bn1), nn.Identity) self.assertEqual(type(model.relu1), nn.Identity) self.assertEqual(type(model.sub1.conv), nnq.Conv2d) self.assertEqual(type(model.sub1.bn), nn.Identity) self.assertEqual(type(model.sub2.conv), nn.Conv2d) self.assertEqual(type(model.sub2.relu), nn.ReLU) self.assertEqual(type(model.bn2), nniq.BNReLU3d) test_only_eval_fn(model, self.img_data_1d) self.checkNoQconfig(model) checkQuantized(model) model = ModelForFusion(default_qconfig).eval() model = fuse_modules( model, [['conv1', 'bn1', 'relu1'], ['conv2', 'relu2'], ['bn2', 'relu3'], ['sub1.conv', 'sub1.bn'], ['conv3', 'bn3', 'relu4']]) model = quantize(model, test_only_eval_fn, [self.img_data_1d]) checkQuantized(model)