示例#1
0
def combine_batchnorm1d_net(
        network: networks.SequentialNetwork) -> networks.SequentialNetwork:
    """
    Utilities function to combine all the FullyConnectedNodes followed by BatchNorm1DNodes in corresponding
    FullyConnectedNodes.
    Parameters
    ----------
    network : SequentialNetwork
        Sequential Network of interest of which we want to combine the nodes.
    Return
    ----------
    SequentialNetwork
        Corresponding Sequential Network with the combined nodes.
    """

    py_net = cv.PyTorchConverter().from_neural_network(network)

    modules = [m for m in py_net.pytorch_network.modules()]
    modules = modules[1:]
    num_modules = len(modules)
    current_index = 0

    new_modules = []

    while current_index + 1 < num_modules:

        current_node = modules[current_index]
        next_node = modules[current_index + 1]

        if isinstance(current_node, ptl.Linear) and isinstance(
                next_node, ptl.BatchNorm1d):
            combined_node = combine_batchnorm1d(current_node, next_node)
            new_modules.append(combined_node)
            current_index = current_index + 1

        elif isinstance(current_node, ptl.Linear):
            new_modules.append(copy.deepcopy(current_node))

        elif isinstance(current_node, ptl.ReLU):
            new_modules.append(copy.deepcopy(current_node))

        else:
            raise Exception(
                "Combine Batchnorm supports only ReLU, Linear and BatchNorm1D layers."
            )

        current_index = current_index + 1

    if not isinstance(modules[current_index], ptl.BatchNorm1d):
        new_modules.append(copy.deepcopy(modules[current_index]))

    temp_pynet = ptl.Sequential(py_net.pytorch_network.identifier,
                                py_net.pytorch_network.input_id, new_modules)
    combined_pynet = cv.PyTorchNetwork(py_net.identifier, temp_pynet)
    combined_network = cv.PyTorchConverter().to_neural_network(combined_pynet)

    return combined_network
示例#2
0
def input_search_lbl(
        net: networks.SequentialNetwork,
        ref_output: Tensor,
        starset_list: List[abst.StarSet],
        max_iter: int,
        threshold: float = 1e-5,
        optimizer_con: type = torch.optim.SGD,
        opt_params: dict = None,
        scheduler_con: type = torch.optim.lr_scheduler.ReduceLROnPlateau,
        scheduler_params: dict = None,
        max_iter_no_change: int = None):

    logger = logging.getLogger(logger_name)
    logger.info(
        f"LAYER-BY-LAYER SEARCH of Input Point corresponding to Output: {ref_output}."
    )

    current_node = net.get_first_node()
    node_list = []
    while current_node is not None:
        node_list.append(current_node)
        current_node = net.get_next_node(current_node)

    node_list.reverse()
    starset_list.reverse()
    temp_ref_output = ref_output

    for i in range(len(node_list)):

        temp_net = networks.SequentialNetwork("temp", "temp")
        temp_net.add_node(copy.deepcopy(node_list[i]))
        temp_start_input = list(starset_list[i].stars)[0].get_samples(1)[0]
        temp_start_input = temp_start_input.squeeze()
        temp_ref_output = temp_ref_output.squeeze()

        logger.info(
            f"ANALYZING LAYER: {node_list[i].identifier}. Starting Input = {temp_start_input}, "
            f"Reference Output = {temp_ref_output}")

        temp_correct, temp_current_input, temp_current_output = input_search(
            temp_net, temp_ref_output, temp_start_input, max_iter, threshold,
            optimizer_con, opt_params, scheduler_con, scheduler_params,
            max_iter_no_change)

        logger.info(
            f"ENDED LAYER SEARCH. FOUND = {temp_correct}, INPUT = {temp_current_input}, "
            f"OUTPUT = {temp_current_output}")

        if not temp_correct:
            logger.info(f"Search Failed at layer: {node_list[i].identifier}")
            return False, None, None

        temp_ref_output = temp_current_input

    py_net = cv.PyTorchConverter().from_neural_network(net).pytorch_network
    py_current_input = torch.from_numpy(temp_current_input)
    py_current_output = py_net(py_current_input)

    return temp_correct, py_current_input.detach().numpy(
    ), py_current_output.detach().numpy()
示例#3
0
def search_cloud(net: networks.NeuralNetwork, ref_output: Tensor,
                 start_input: Tensor, num_samples: int, scale: Tensor):

    py_net = cv.PyTorchConverter().from_neural_network(net).pytorch_network
    py_ref_output = torch.from_numpy(ref_output).squeeze()
    py_current_input = torch.from_numpy(start_input).squeeze()
    py_current_output = py_net(py_current_input)
    best_dist = torch.dist(py_ref_output, py_current_output, p=2)
    current_input = start_input
    best_sample = start_input

    for i in range(num_samples):

        sample = np.random.normal(loc=current_input,
                                  scale=scale,
                                  size=current_input.shape)
        py_sample = torch.from_numpy(sample).squeeze()
        py_output = py_net(py_sample)
        temp_dist = torch.dist(py_ref_output, py_output, p=2)
        if temp_dist.item() < best_dist.item():
            best_sample = sample
            best_dist = temp_dist

    current_input = best_sample
    current_output = py_net(
        torch.from_numpy(current_input).squeeze()).detach().numpy()
    current_output = np.expand_dims(current_output, axis=1)
    current_dist = best_dist.item()

    return current_input, current_output, current_dist
示例#4
0
    def train(self, network: networks.NeuralNetwork, dataset: datasets.Dataset) -> networks.NeuralNetwork:
        """
        Train the neural network of interest using the training strategy SGD Training.

        Parameters
        ----------
        network : NeuralNetwork
            The neural network to train.
        dataset : Dataset
            The dataset to use for the training of the network.

        Returns
        ----------
        NeuralNetwork
            The Neural Network resulting from the application of the training strategy to the original network.

        """

        pytorch_converter = cv.PyTorchConverter()
        py_net = pytorch_converter.from_neural_network(network)

        py_net = self.__training(py_net, dataset)

        network.alt_rep_cache.clear()
        network.alt_rep_cache.append(py_net)
        network.up_to_date = False

        return network
示例#5
0
    def test(self, network: networks.NeuralNetwork,
             dataset: datasets.Dataset) -> float:

        pytorch_converter = cv.PyTorchConverter()
        py_net = pytorch_converter.from_neural_network(network)

        measure = self.__testing(py_net, dataset)

        return measure
示例#6
0
def compute_saliency(net: networks.NeuralNetwork, ref_input: Tensor):
    class BackHook:
        def __init__(self, module: torch.nn.Module, backward=True):
            if backward:
                self.hook = module.register_backward_hook(self.hook_fn)
            else:
                self.hook = module.register_forward_hook(self.hook_fn)
            self.m_input = None
            self.m_output = None

        def hook_fn(self, module, m_input, m_output):
            self.m_input = m_input
            self.m_output = m_output

        def close(self):
            self.hook.remove()

    py_net = cv.PyTorchConverter().from_neural_network(net).pytorch_network

    # We register the hooks on the modules of the networks
    backward_hooks = [BackHook(layer) for layer in py_net.modules()]
    forward_hooks = [BackHook(layer, False) for layer in py_net.modules()]

    ref_input = torch.from_numpy(ref_input)
    ref_input.requires_grad = True
    out = py_net(ref_input)
    i = 0
    print("FORWARD HOOKS")
    for m in py_net.modules():
        hook = forward_hooks[i]
        print(m)
        print("INPUT")
        print(hook.m_input)
        print("OUTPUT")
        print(hook.m_output)
        i = i + 1
    for k in range(len(out)):
        print(f"Variable {k} of output")
        out = py_net(ref_input)
        out[k].backward(retain_graph=True)
        print("INPUT GRAD:" + f"{ref_input.grad}")

        i = 0
        for m in py_net.modules():
            hook = backward_hooks[i]
            print(m)
            print("INPUT")
            print(hook.m_input[0])
            print("OUTPUT")
            print(hook.m_output[0])
            i = i + 1

    print(out)
    ref_input[0] = ref_input[0] + 10
    out = py_net(ref_input)
    print(out)
示例#7
0
    def train(self, network: networks.NeuralNetwork,
              dataset: datasets.Dataset) -> networks.NeuralNetwork:

        pytorch_converter = cv.PyTorchConverter()
        py_net = pytorch_converter.from_neural_network(network)

        py_net = self.__training(py_net, dataset)

        network.alt_rep_cache.clear()
        network.alt_rep_cache.append(py_net)
        network.up_to_date = False

        return network
示例#8
0
def net_update(network: networks.NeuralNetwork) -> networks.NeuralNetwork:

    if not network.up_to_date:

        for alt_rep in network.alt_rep_cache:

            if alt_rep.up_to_date:
                if isinstance(alt_rep, cv.ONNXNetwork):
                    return cv.ONNXConverter().to_neural_network(alt_rep)
                elif isinstance(alt_rep, cv.PyTorchNetwork):
                    return cv.PyTorchConverter().to_neural_network(alt_rep)
                else:
                    raise NotImplementedError

    else:
        return network
示例#9
0
    def prune(self, network: networks.NeuralNetwork,
              dataset: datasets.Dataset) -> networks.NeuralNetwork:
        """
        Prune the neural network of interest using the pruning strategy Weight Pruning.

        Parameters
        ----------
        network : NeuralNetwork
            The neural network to prune.
        dataset : Dataset
            The dataset to use for the pre-training and fine-tuning procedure.

        Returns
        ----------
        NeuralNetwork
            The Neural Network resulting from the application of the pruning strategy to the original network.

        """

        if self.training_strategy is not None and self.pre_training:
            fine_tuning = self.training_strategy.fine_tuning
            self.training_strategy.fine_tuning = False
            network = self.training_strategy.train(network, dataset)
            self.training_strategy.fine_tuning = fine_tuning

        pytorch_converter = cv.PyTorchConverter()
        py_net = pytorch_converter.from_neural_network(network)

        py_net = self.__pruning(py_net)

        network.alt_rep_cache.clear()
        network.alt_rep_cache.append(py_net)
        network.up_to_date = False

        if self.training_strategy is not None and self.training_strategy.fine_tuning:
            old_l1_decay = self.training_strategy.l1_decay
            old_batchnorm_decay = self.training_strategy.batchnorm_decay
            self.training_strategy.l1_decay = 0
            self.training_strategy.batchnorm_decay = 0
            network = self.training_strategy.train(network, dataset)
            self.training_strategy.l1_decay = old_l1_decay
            self.training_strategy.batchnorm_decay = old_batchnorm_decay

        return network
示例#10
0
                    in_pred_bias.append([-norm_input_lb[m]])
                    in_pred_bias.append([norm_input_ub[m]])

                in_pred_bias = np.array(in_pred_bias)
                in_pred_mat = np.array(in_pred_mat)
                out_pred_mat = np.array(unsafe_mats[k])
                out_pred_bias = np.array(unsafe_vecs[k])

                prop = ver.NeVerProperty(in_pred_mat, in_pred_bias,
                                         [out_pred_mat], [out_pred_bias])
                # prop = ver.NeVerProperty(in_pred_mat, in_pred_bias, unsafe_mats, unsafe_vecs)

                input_prefix = network.input_id
                output_prefix = network.get_last_node().identifier
                ver.temp_never2smt(prop, input_prefix, output_prefix,
                                   f"smt_property/SMT_{p_id[k]}.smt2")

                p2 = reading.SmtPropertyParser(
                    ver.SMTLIBProperty(f"smt_property/SMT_{p_id[k]}.smt2"),
                    input_prefix, output_prefix).parse_property()
                print(p2)

            prop_set = True

        onnx_net = conv.ONNXConverter().from_neural_network(network)
        pytorch_net = conv.PyTorchConverter().from_neural_network(network)
        torch.save(pytorch_net.pytorch_network,
                   f"acas_pytorch/{network.identifier}.pt")
        onnx.save(onnx_net.onnx_network,
                  f"acas_onnx/{network.identifier}.onnx")
示例#11
0
def combine_batchnorm1d_net(
        network: networks.SequentialNetwork) -> networks.SequentialNetwork:
    """
    Utilities function to combine all the FullyConnectedNodes followed by BatchNorm1DNodes in corresponding
    FullyConnectedNodes.

    Parameters
    ----------
    network : SequentialNetwork
        Sequential Network of interest of which we want to combine the nodes.

    Return
    ----------
    SequentialNetwork
        Corresponding Sequential Network with the combined nodes.

    """

    if not network.up_to_date:

        for alt_rep in network.alt_rep_cache:

            if alt_rep.up_to_date:

                if isinstance(alt_rep, cv.PyTorchNetwork):
                    pytorch_cv = cv.PyTorchConverter()
                    network = pytorch_cv.to_neural_network(alt_rep)
                elif isinstance(alt_rep, cv.ONNXNetwork):
                    onnx_cv = cv.ONNXConverter
                    network = onnx_cv.to_neural_network(alt_rep)
                else:
                    raise NotImplementedError
                break

    combined_network = networks.SequentialNetwork(network.identifier +
                                                  '_combined')

    current_node = network.get_first_node()
    node_index = 1
    while network.get_next_node(
            current_node) is not None and current_node is not None:

        next_node = network.get_next_node(current_node)
        if isinstance(current_node, nodes.FullyConnectedNode) and isinstance(
                next_node, nodes.BatchNorm1DNode):
            combined_node = combine_batchnorm1d(current_node, next_node)
            combined_node.identifier = f"Combined_Linear_{node_index}"
            combined_network.add_node(combined_node)
            next_node = network.get_next_node(next_node)

        elif isinstance(current_node, nodes.FullyConnectedNode):
            identifier = f"Linear_{node_index}"
            new_node = nodes.FullyConnectedNode(identifier,
                                                current_node.in_features,
                                                current_node.out_features,
                                                current_node.weight,
                                                current_node.bias)
            combined_network.add_node(new_node)

        elif isinstance(current_node, nodes.ReLUNode):
            identifier = f"ReLU_{node_index}"
            new_node = nodes.ReLUNode(identifier, current_node.num_features)
            combined_network.add_node(new_node)
        else:
            raise NotImplementedError

        node_index += 1
        current_node = next_node

    if isinstance(current_node, nodes.FullyConnectedNode):
        identifier = f"Linear_{node_index}"
        new_node = nodes.FullyConnectedNode(identifier,
                                            current_node.in_features,
                                            current_node.out_features,
                                            current_node.weight,
                                            current_node.bias)
        combined_network.add_node(new_node)
    elif isinstance(current_node, nodes.ReLUNode):
        identifier = f"ReLU_{node_index}"
        new_node = nodes.ReLUNode(identifier, current_node.num_features)
        combined_network.add_node(new_node)
    else:
        raise NotImplementedError

    return combined_network
示例#12
0
baseline_net = trainer_baseline.train(baseline_net, dataset)

sparse_net = copy.deepcopy(small_net)
sparse_net = trainer_ns.train(sparse_net, dataset)
trainer_ns.fine_tuning = True

wp_pruner = pruning.WeightPruning(weight_sparsity_rate, trainer_wp, pre_training=True)
ns_pruner = pruning.NetworkSlimming(neuron_sparsity_rate, trainer_ns, pre_training=False)

wp_pruned_net = copy.deepcopy(small_net)
wp_pruned_net = wp_pruner.prune(wp_pruned_net, dataset)

ns_pruned_net = copy.deepcopy(sparse_net)
ns_pruned_net = ns_pruner.prune(ns_pruned_net, dataset)

baseline_accuracy, baseline_loss = util.testing(conversion.PyTorchConverter().from_neural_network(baseline_net),
                                                dataset, test_batch_size, cuda=cuda)
sparse_accuracy, sparse_loss = util.testing(conversion.PyTorchConverter().from_neural_network(sparse_net),
                                            dataset, test_batch_size, cuda=cuda)
ns_accuracy, ns_loss = util.testing(conversion.PyTorchConverter().from_neural_network(ns_pruned_net),
                                    dataset, test_batch_size, cuda=cuda)
wp_accuracy, wp_loss = util.testing(conversion.PyTorchConverter().from_neural_network(wp_pruned_net),
                                    dataset, test_batch_size, cuda=cuda)


# Batch norm fusion for the networks of interest (needed for verification and abstraction).
com_baseline = util.combine_batchnorm1d_net(baseline_net)
com_sparse_net = util.combine_batchnorm1d_net(sparse_net)
com_wp_pruned_net = util.combine_batchnorm1d_net(wp_pruned_net)
com_ns_pruned_net = util.combine_batchnorm1d_net(ns_pruned_net)
示例#13
0
    print("DROPOUT NODE TEST")
    start_network = network.SequentialNetwork("NET_TEST", "X")
    start_network.add_node(nodes.DropoutNode("Dropout_1", (3, 4, 5, 6)))
    alt_network = converter.from_neural_network(start_network)
    end_network = converter.to_neural_network(alt_network)
    assert isinstance(end_network, network.SequentialNetwork)
    start_node = start_network.get_first_node()
    end_node = end_network.get_first_node()

    assert isinstance(start_node, nodes.DropoutNode)
    assert isinstance(end_node, nodes.DropoutNode)
    assert start_node.p == end_node.p
    assert start_node.identifier == end_node.identifier


converters = [conversion.ONNXConverter(), conversion.PyTorchConverter()]
for conv in converters:
    print(f"Test for {conv.__class__.__name__}")
    relu_node_test(conv)
    sigmoid_node_test(conv)
    fully_connected_node_test(conv, True)
    fully_connected_node_test(conv, False)
    batchnorm_node_test(conv)
    conv_node_test(conv, True)
    conv_node_test(conv, False)
    averagepool_node_test(conv)
    maxpool_node_test(conv)
    lrn_node_test(conv)
    softmax_node_test(conv)
    unsqueeze_node_test(conv)
    reshape_node_test(conv)
示例#14
0
    def analyze(self, network: networks.NeuralNetwork, sample: Tensor) -> List:
        """
        Analyze the Neural Network with respect to the input Tensor of interest. It returns a list of list containing
        the relevance value for the hidden layers ReLU neurons.

        Parameters
        ----------
        network : NeuralNetwork
            The network to analyze to extract the relevances of the ReLU neurons.
        sample : Tensor
            The data sample which is used to compute the relevances.

        Returns
        -------
        List
            List containing the relevances for each neuron of each ReLU hidden layer.

        """

        pyt_net = conv.PyTorchConverter().from_neural_network(
            network).pytorch_network
        pyt_net.float()
        pyt_sample = torch.Tensor(sample).squeeze()

        pyt_net.eval()
        activations = []
        layers = []

        current_activations = pyt_sample
        activations.append(current_activations)

        last_module = 0
        for m in pyt_net.modules():
            last_module = last_module + 1

        m_index = 0
        for m in pyt_net.modules():

            if isinstance(m, pyt_layers.Linear):

                current_activations = m(current_activations)
                if self.lrp_rule is None:
                    layers.append(m)
                else:
                    layers.append(self.lrp_rule(m))

            elif isinstance(m, pyt_layers.ReLU) and m_index < last_module - 1:

                current_activations = m(current_activations)
                activations.append(current_activations)

            m_index += 1

        activations.reverse()
        layers.reverse()

        # We begin with setting the relevances to the values of the output
        relevances = [pyt_net(pyt_sample)]
        current_relevance = relevances[0]
        for i in range(len(activations)):
            current_relevance = self.__rel_prop_mat(activations[i], layers[i],
                                                    current_relevance)
            relevances.append(current_relevance)

        for i in range(len(relevances)):
            relevances[i] = relevances[i].detach().numpy()

        relevances.reverse()
        return relevances
示例#15
0
def input_search(
        net: networks.NeuralNetwork,
        ref_output: Tensor,
        start_input: Tensor,
        max_iter: int,
        threshold: float = 1e-5,
        optimizer_con: type = torch.optim.SGD,
        opt_params: dict = None,
        scheduler_con: type = torch.optim.lr_scheduler.ReduceLROnPlateau,
        scheduler_params: dict = None,
        max_iter_no_change: int = None):

    logger = logging.getLogger(logger_name)
    logger.info(
        f"SEARCH of Input Point corresponding to Output: {ref_output}. MAX_ITER = {max_iter}\n"
    )

    if opt_params is None:
        opt_params = dict(lr=0.1, momentum=0.5)

    if max_iter_no_change is None:
        max_iter_no_change = int(max_iter / 10)

    py_net = cv.PyTorchConverter().from_neural_network(net).pytorch_network
    py_ref_output = torch.from_numpy(ref_output)
    py_start_input = torch.from_numpy(start_input)
    current_input = py_start_input
    current_input.requires_grad = True

    optim = optimizer_con([current_input], **opt_params)

    if scheduler_params is None:
        scheduler = scheduler_con(optim)
    else:
        scheduler = scheduler_con(optim, **scheduler_params)

    dist = torch.Tensor([threshold + 10])
    iteration = 0
    iter_no_change = 0
    last_dist = dist
    while dist > threshold and iteration < max_iter:

        current_output = py_net(current_input)
        current_output = torch.unsqueeze(current_output, 0)
        dist = funct.pairwise_distance(py_ref_output, current_output, p=2)

        if abs(dist.item() - last_dist.item()) < 0.000001:
            iter_no_change += 1

        if iter_no_change > max_iter_no_change:
            logger.debug("Early Stopping")
            break

        optim.zero_grad()
        dist.backward()
        optim.step()
        scheduler.step(dist)

        logger.debug(f"Iter {iteration}, PW_Dist = {dist.item()}")
        logger.debug(f"Current Input: {current_input.data}")
        logger.debug(f"Current Output: {current_output.data}")
        logger.debug(f"Current Reference Output: {py_ref_output.data}\n")
        last_dist = dist
        iteration = iteration + 1

    correct = False
    if dist <= threshold:
        correct = True

    return correct, current_input.detach().numpy(), current_output.detach(
    ).numpy()